<commit_before>/*
 * Copyright 2014-2021 TNG Technology Consulting GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.tngtech.archunit.core.domain;

import java.lang.annotation.Annotation;
import java.util.Map;

import com.google.common.collect.ImmutableMap;
import com.tngtech.archunit.PublicAPI;
import com.tngtech.archunit.base.HasDescription;
import com.tngtech.archunit.base.Optional;
import com.tngtech.archunit.core.domain.properties.CanBeAnnotated;
import com.tngtech.archunit.core.domain.properties.HasOwner;
import com.tngtech.archunit.core.domain.properties.HasType;
import com.tngtech.archunit.core.importer.DomainBuilders.JavaAnnotationBuilder;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.tngtech.archunit.PublicAPI.Usage.ACCESS;
import static com.tngtech.archunit.PublicAPI.Usage.INHERITANCE;

/**
 * Represents an imported annotation on an annotated object like a class or a method. To be
 * independent of the classpath, all properties of this annotation are just stored as a simple
 * key value pairs. I.e. if you consider
 * <pre><code>
 *  {@literal @}MyAnnotation(name = "some name", anAttribute = 7)
 *  class MyClass {}
 * </code></pre>
 * this annotation will be imported storing the association
 * <pre><code>
 *   name &rarr; "some name"
 *   anAttribute &rarr; 7
 * </code></pre>
 * Properties will be made available via {@link #get(String)}, e.g.
 * <pre><code>
 *   myAnnotation.get("anAttribute")
 * </code></pre>
 * will return the value 7. Since this behavior is inconvenient (loss of type safety),
 * there is another approach to retrieve these values, if the annotation can
 * be resolved on the classpath. It's then possible to access a simple proxy
 * <pre><code>
 *   MyAnnotation moreConvenient = myAnnotation.as(MyAnnotation.class);
 *   moreConvenient.anAttribute(); // &rarr; returns 7
 * </code></pre>
 * ----------<br>
 * NOTE<br>
 * ----------<br>
 * ArchUnit holds the annotation in a classpath independent representation, i.e. some types will
 * be mapped, when the access is proxied. Consider
 * <pre><code>
 *  {@literal @}SomeAnnotation(type = String.class)
 *  class MyClass {}
 * </code></pre>
 * Accesses to 'type' will be different for the proxied version:
 * <pre><code>
 *   someAnnotation.get("type"); // &rarr; returns JavaClass{String}
 *   someAnnotation.as(SomeAnnotation.class).type(); // &rarr; returns String.class
 * </code></pre>
 *
 * @param <OWNER> The type of the closest "parent" of this annotation. If this annotation
 *                is annotated on a class or member, it is that class or member. If this
 *                annotation is a member of another annotation, it is that annotation.
 */
public final class JavaAnnotation<OWNER extends HasDescription> implements HasType, HasOwner<OWNER>, HasDescription {
    private final JavaClass type;
    private final OWNER owner;
    private final CanBeAnnotated annotatedElement;
    private final String description;
    private final Map<String, Object> values;

    private JavaAnnotation(JavaClass type, OWNER owner, CanBeAnnotated annotatedElement, String description, Map<String, Object> values) {
        this.type = checkNotNull(type);
        this.owner = checkNotNull(owner);
        this.annotatedElement = checkNotNull(annotatedElement);
        this.description = checkNotNull(description);
        this.values = checkNotNull(values);
    }

    JavaAnnotation(OWNER owner, JavaAnnotationBuilder builder) {
        this.type = checkNotNull(builder.getType());
        this.owner = checkNotNull(owner);
        this.annotatedElement = getAnnotatedElement(owner);
        this.description = createDescription();
        this.values = checkNotNull(builder.getValues(this));
    }

    private static CanBeAnnotated getAnnotatedElement(Object owner) {
        Object candiate = owner;
        while (!(candiate instanceof JavaClass) && !(candiate instanceof JavaMember) && (candiate instanceof HasOwner<?>)) {<commit_msg>find annotated element by looking for `CanBeAnnotated` on owner<commit_after>/*
 * Copyright 2014-2021 TNG Technology Consulting GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.tngtech.archunit.core.domain;

import java.lang.annotation.Annotation;
import java.util.Map;

import com.google.common.collect.ImmutableMap;
import com.tngtech.archunit.PublicAPI;
import com.tngtech.archunit.base.HasDescription;
import com.tngtech.archunit.base.Optional;
import com.tngtech.archunit.core.domain.properties.CanBeAnnotated;
import com.tngtech.archunit.core.domain.properties.HasOwner;
import com.tngtech.archunit.core.domain.properties.HasType;
import com.tngtech.archunit.core.importer.DomainBuilders.JavaAnnotationBuilder;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.tngtech.archunit.PublicAPI.Usage.ACCESS;
import static com.tngtech.archunit.PublicAPI.Usage.INHERITANCE;

/**
 * Represents an imported annotation on an annotated object like a class or a method. To be
 * independent of the classpath, all properties of this annotation are just stored as a simple
 * key value pairs. I.e. if you consider
 * <pre><code>
 *  {@literal @}MyAnnotation(name = "<NAME>", anAttribute = 7)
 *  class MyClass {}
 * </code></pre>
 * this annotation will be imported storing the association
 * <pre><code>
 *   name &rarr; "some name"
 *   anAttribute &rarr; 7
 * </code></pre>
 * Properties will be made available via {@link #get(String)}, e.g.
 * <pre><code>
 *   myAnnotation.get("anAttribute")
 * </code></pre>
 * will return the value 7. Since this behavior is inconvenient (loss of type safety),
 * there is another approach to retrieve these values, if the annotation can
 * be resolved on the classpath. It's then possible to access a simple proxy
 * <pre><code>
 *   MyAnnotation moreConvenient = myAnnotation.as(MyAnnotation.class);
 *   moreConvenient.anAttribute(); // &rarr; returns 7
 * </code></pre>
 * ----------<br>
 * NOTE<br>
 * ----------<br>
 * ArchUnit holds the annotation in a classpath independent representation, i.e. some types will
 * be mapped, when the access is proxied. Consider
 * <pre><code>
 *  {@literal @}SomeAnnotation(type = String.class)
 *  class MyClass {}
 * </code></pre>
 * Accesses to 'type' will be different for the proxied version:
 * <pre><code>
 *   someAnnotation.get("type"); // &rarr; returns JavaClass{String}
 *   someAnnotation.as(SomeAnnotation.class).type(); // &rarr; returns String.class
 * </code></pre>
 *
 * @param <OWNER> The type of the closest "parent" of this annotation. If this annotation
 *                is annotated on a class or member, it is that class or member. If this
 *                annotation is a member of another annotation, it is that annotation.
 */
public final class JavaAnnotation<OWNER extends HasDescription> implements HasType, HasOwner<OWNER>, HasDescription {
    private final JavaClass type;
    private final OWNER owner;
    private final CanBeAnnotated annotatedElement;
    private final String description;
    private final Map<String, Object> values;

    private JavaAnnotation(JavaClass type, OWNER owner, CanBeAnnotated annotatedElement, String description, Map<String, Object> values) {
        this.type = checkNotNull(type);
        this.owner = checkNotNull(owner);
        this.annotatedElement = checkNotNull(annotatedElement);
        this.description = checkNotNull(description);
        this.values = checkNotNull(values);
    }

    JavaAnnotation(OWNER owner, JavaAnnotationBuilder builder) {
        this.type = checkNotNull(builder.getType());
        this.owner = checkNotNull(owner);
        this.annotatedElement = getAnnotatedElement(owner);
        this.description = createDescription();
        this.values = checkNotNull(builder.getValues(this));
    }

    private static CanBeAnnotated getAnnotatedElement(Object owner) {
        Object candiate = owner;
        while (!(candiate instanceof CanBeAnnotated) && (candiate instanceof HasOwner<?>)) {
{'fraction_non_alphanumeric': 0.10484485574305934, 'fraction_numerical': 0.0034839412084921068, 'mean_word_length': 4.008724100327154, 'pattern_counts': {'":': 0, '<': 70, '<?xml version=': 0, '>': 70, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '535649', 'n_tokens_mistral': 2588, 'n_tokens_neox': 2498, 'n_words': 844}