All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.smallrye.graphql.client.model.Annotations Maven / Gradle / Ivy

There is a newer version: 2.12.0
Show newest version
package io.smallrye.graphql.client.model;

import static java.util.Collections.emptyMap;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget.Kind;
import org.jboss.jandex.AnnotationValue;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.FieldInfo;
import org.jboss.jandex.MethodInfo;
import org.jboss.jandex.MethodParameterInfo;
import org.jboss.jandex.Type;

public class Annotations {
    // todo: maybe use some of the helper methods in this class
    private final Map annotationsMap;

    public final Map parentAnnotations;

    /**
     * Get used when creating operations.
     * Operation only have methods (no properties)
     *
     * @param methodInfo the java method
     * @return Annotations for this method and its return-type
     */
    public static Annotations getAnnotationsForMethod(MethodInfo methodInfo) {
        Map annotationMap = new HashMap<>();

        for (AnnotationInstance annotationInstance : methodInfo.annotations()) {
            DotName name = annotationInstance.name();
            Kind kind = annotationInstance.target().kind();
            if (kind.equals(Kind.METHOD)) {
                annotationMap.put(name, annotationInstance);
            }
        }

        final Type type = methodInfo.returnType();
        if (Classes.isParameterized(type)) {
            Type wrappedType = type.asParameterizedType().arguments().get(0);
            for (final AnnotationInstance annotationInstance : wrappedType.annotations()) {
                DotName name = annotationInstance.name();
                annotationMap.put(name, annotationInstance);
            }
        }

        Map parentAnnotations = getParentAnnotations(methodInfo.declaringClass());

        return new Annotations(annotationMap, parentAnnotations);
    }

    private static Map getParentAnnotations(FieldInfo fieldInfo, MethodInfo methodInfo) {
        ClassInfo declaringClass = fieldInfo != null ? fieldInfo.declaringClass() : methodInfo.declaringClass();
        return getParentAnnotations(declaringClass);
    }

    private static Map getParentAnnotations(ClassInfo classInfo) {
        Map parentAnnotations = new HashMap<>();

        for (AnnotationInstance classAnnotation : classInfo.declaredAnnotations()) {
            parentAnnotations.putIfAbsent(classAnnotation.name(), classAnnotation);
        }

        Map packageAnnotations = getPackageAnnotations(classInfo);
        for (DotName dotName : packageAnnotations.keySet()) {
            parentAnnotations.putIfAbsent(dotName, packageAnnotations.get(dotName));
        }

        return parentAnnotations;
    }

    private static Map getPackageAnnotations(ClassInfo classInfo) {
        Map packageAnnotations = new HashMap<>();

        DotName packageName = packageInfo(classInfo);
        if (packageName != null) {
            ClassInfo packageInfo = ScanningContext.getIndex().getClassByName(packageName);
            if (packageInfo != null) {
                for (AnnotationInstance packageAnnotation : packageInfo.declaredAnnotations()) {
                    packageAnnotations.putIfAbsent(packageAnnotation.name(), packageAnnotation);
                }
            }
        }

        return packageAnnotations;
    }

    private static DotName packageInfo(ClassInfo classInfo) {
        String className = classInfo.name().toString();
        int index = className.lastIndexOf('.');
        if (index == -1) {
            return null;
        }
        return DotName.createSimple(className.substring(0, index) + ".package-info");
    }

    /**
     * Get used when we create types and references to them
     * 

* Class level annotation for type creation. * * @param classInfo the java class * @return annotation for this class */ public static Annotations getAnnotationsForClass(ClassInfo classInfo) { Map annotationMap = new HashMap<>(); for (AnnotationInstance annotationInstance : classInfo.declaredAnnotations()) { DotName name = annotationInstance.name(); annotationMap.put(name, annotationInstance); } Map packageAnnotations = getPackageAnnotations(classInfo); for (DotName dotName : packageAnnotations.keySet()) { annotationMap.putIfAbsent(dotName, packageAnnotations.get(dotName)); } return new Annotations(annotationMap, packageAnnotations); } /** * Get used when creating arrays. *

* This will contains the annotation on the collection field and method * * @param typeInCollection the field java type * @param methodTypeInCollection the method java type * @return the annotation for this array */ public static Annotations getAnnotationsForArray(Type typeInCollection, Type methodTypeInCollection) { Map annotationMap = getAnnotationsForType(typeInCollection); annotationMap.putAll(getAnnotationsForType(methodTypeInCollection)); return new Annotations(annotationMap); } // /** * Used when we are creating operation and arguments for these operations * * @param methodInfo the java method * @param pos the argument position * @return annotation for this argument */ public static Annotations getAnnotationsForArgument(MethodInfo methodInfo, short pos) { if (pos >= methodInfo.parametersCount()) { throw new IndexOutOfBoundsException( "Parameter at position " + pos + " not found on method " + methodInfo.name()); } final Type parameterType = methodInfo.parameterType(pos); Map annotationMap = getAnnotations(parameterType); for (AnnotationInstance anno : methodInfo.annotations()) { if (anno.target().kind().equals(Kind.METHOD_PARAMETER)) { MethodParameterInfo methodParameter = anno.target().asMethodParameter(); short position = methodParameter.position(); if (position == pos) { annotationMap.put(anno.name(), anno); } } } final Map parentAnnotations = getParentAnnotations(methodInfo.declaringClass()); return new Annotations(annotationMap, parentAnnotations); } public static boolean isJsonBAnnotation(AnnotationInstance instance) { return instance.name().toString().startsWith(JAKARTA_JSONB) || instance.name().toString().startsWith(JAVAX_JSONB); } // ------- All static creators done, now the actual class -------- private Annotations(Map annotations) { this(annotations, new HashMap<>()); } /** * Create the annotations, mapped by name * * @param annotations the annotation */ private Annotations(Map annotations, Map parentAnnotations) { this.annotationsMap = annotations; this.parentAnnotations = parentAnnotations; } public Set getAnnotationNames() { return annotationsMap.keySet(); } public Annotations removeAnnotations(DotName... annotations) { Map newAnnotationsMap = new HashMap<>(annotationsMap); for (DotName annotation : annotations) { newAnnotationsMap.remove(annotation); } return new Annotations(newAnnotationsMap, this.parentAnnotations); } /** * Get a specific annotation * * @param annotation the annotation you want * @return the annotation value or null */ public AnnotationValue getAnnotationValue(DotName annotation) { return this.annotationsMap.get(annotation).value(); } /** * Get a specific annotation * * @param annotation the annotation you want * @param name the name of the field that you want the value of * @return the annotation value or null */ public AnnotationValue getAnnotationValue(DotName annotation, String name) { return this.annotationsMap.get(annotation).value(name); } /** * Check if there is an annotation and it has a valid value * * @param annotation the annotation we are checking * @return true if valid value */ public boolean containsKeyAndValidValue(DotName annotation) { return this.annotationsMap.containsKey(annotation) && this.annotationsMap.get(annotation).value() != null; } /** * Check if one of these annotations is present * * @param annotations the annotations to check * @return true if it does */ public boolean containsOneOfTheseAnnotations(DotName... annotations) { for (DotName name : annotations) { if (this.annotationsMap.containsKey(name)) { return true; } } return false; } public boolean containsOneOfTheseInheritableAnnotations(DotName... annotations) { for (DotName name : annotations) { if (this.parentAnnotations.containsKey(name)) { return true; } } return false; } /** * Get on of these annotations * * @param annotations the annotations to check (in order) * @return the annotation potentially or empty if not found */ public Optional getOneOfTheseAnnotations(DotName... annotations) { for (DotName name : annotations) { if (this.annotationsMap.containsKey(name)) { return Optional.of(this.annotationsMap.get(name)); } } return Optional.empty(); } /** * This go through a list of annotations and find the first one that has a valid value. * If it could not find one, it return empty * * @param annotations the annotations in order * @return the valid annotation value or default value */ public Optional getOneOfTheseAnnotationsValue(DotName... annotations) { for (DotName dotName : annotations) { if (dotName != null && containsKeyAndValidValue(dotName)) { return getStringValue(dotName); } } return Optional.empty(); } /** * This go through a list of method annotations and find the first one that has a valid value. * If it could not find one, it return the default value. * * @param annotations the annotations in order * @return the valid annotation value or empty */ public Optional getOneOfTheseMethodAnnotationsValue(DotName... annotations) { for (DotName dotName : annotations) { if (dotName != null && hasValidMethodAnnotation(dotName)) { return getStringValue(dotName); } } return Optional.empty(); } /** * This go through a list of method parameter annotations and find the first one that has a valid value. * If it could not find one, it return the default value. * * @param annotations the annotations in order * @return the valid annotation value or empty */ public Optional getOneOfTheseMethodParameterAnnotationsValue(DotName... annotations) { for (DotName dotName : annotations) { if (dotName != null && hasValidMethodParameterAnnotation(dotName)) { return getStringValue(dotName); } } return Optional.empty(); } /** * Get a stream of that annotation, maybe empty if not present, maybe a stream of one, or maybe several, if it's repeatable. * * @param name dotname of the annotation */ public Stream resolve(DotName name) { var annotationInstance = annotationsMap.get(name); if (annotationInstance == null) { var repeatableType = ScanningContext.getIndex().getClassByName(name); if (repeatableType.hasAnnotation(REPEATABLE)) { DotName containerName = repeatableType.annotation(REPEATABLE).value().asClass().name(); AnnotationInstance containerAnnotation = annotationsMap.get(containerName); if (containerAnnotation != null) { return Stream.of(containerAnnotation.value().asNestedArray()); } } return Stream.of(); } return Stream.of(annotationInstance); } @Override public String toString() { return annotationsMap.toString(); } private boolean hasValidMethodAnnotation(DotName annotation) { return containsKeyAndValidValue(annotation) && isMethodAnnotation(getAnnotation(annotation)); } private boolean hasValidMethodParameterAnnotation(DotName annotation) { return containsKeyAndValidValue(annotation) && isMethodParameterAnnotation(getAnnotation(annotation)); } private AnnotationInstance getAnnotation(DotName key) { return this.annotationsMap.get(key); } private Optional getStringValue(DotName annotation) { AnnotationInstance annotationInstance = getAnnotation(annotation); if (annotationInstance != null) { return getStringValue(annotationInstance); } return Optional.empty(); } private Optional getStringValue(AnnotationInstance annotationInstance) { AnnotationValue value = annotationInstance.value(); if (value != null) { return getStringValue(value); } return Optional.empty(); } private Optional getStringValue(AnnotationValue annotationValue) { String value; if (annotationValue != null) { value = annotationValue.asString(); if (value != null && !value.isEmpty()) { return Optional.of(value); } } return Optional.empty(); } // Private static methods use by the static initializers private static boolean isMethodAnnotation(AnnotationInstance instance) { return instance.target().kind().equals(Kind.METHOD); } private static boolean isMethodParameterAnnotation(AnnotationInstance instance) { return instance.target().kind().equals(Kind.METHOD_PARAMETER); } private static Annotations getAnnotationsForInputField(FieldInfo fieldInfo, MethodInfo methodInfo) { Map annotationsForField = getAnnotationsForField(fieldInfo, methodInfo); if (fieldInfo != null) { annotationsForField.putAll(getTypeUseAnnotations(fieldInfo.type())); } if (methodInfo != null) { List parameters = methodInfo.parameterTypes(); if (!parameters.isEmpty()) { Type param = parameters.get(ZERO); annotationsForField.putAll(getTypeUseAnnotations(param)); } } final Map parentAnnotations = getParentAnnotations(fieldInfo, methodInfo); return new Annotations(annotationsForField, parentAnnotations); } private static Annotations getAnnotationsForOutputField(FieldInfo fieldInfo, MethodInfo methodInfo) { Map annotationsForField = getAnnotationsForField(fieldInfo, methodInfo); if (fieldInfo != null) { annotationsForField.putAll(getTypeUseAnnotations(fieldInfo.type())); } if (methodInfo != null) { Type returnType = methodInfo.returnType(); if (returnType != null) { annotationsForField.putAll(getTypeUseAnnotations(methodInfo.returnType())); } } Map parentAnnotations = getParentAnnotations(fieldInfo, methodInfo); return new Annotations(annotationsForField, parentAnnotations); } private static Map getTypeUseAnnotations(Type type) { if (type != null) { return getAnnotationsWithFilter(type, Annotations.DATE_FORMAT, Annotations.NUMBER_FORMAT); } return emptyMap(); } private static Map getAnnotations(Type type) { Map annotationMap = new HashMap<>(); if (type.kind().equals(Type.Kind.PARAMETERIZED_TYPE)) { Type typeInCollection = type.asParameterizedType().arguments().get(0); annotationMap.putAll(getAnnotations(typeInCollection)); } else { List annotations = type.annotations(); for (AnnotationInstance annotationInstance : annotations) { annotationMap.put(annotationInstance.name(), annotationInstance); } } return annotationMap; } private static Map getAnnotationsForType(Type type) { Map annotationMap = new HashMap<>(); for (AnnotationInstance annotationInstance : type.annotations()) { DotName name = annotationInstance.name(); annotationMap.put(name, annotationInstance); } return annotationMap; } private static Map getAnnotationsForField(FieldInfo fieldInfo, MethodInfo methodInfo) { Map annotationMap = new HashMap<>(); if (fieldInfo != null) annotationMap.putAll(listToMap(fieldInfo.annotations().stream() .filter(ai -> ai.target().kind() == Kind.FIELD) .collect(Collectors.toList()))); if (methodInfo != null) annotationMap.putAll(listToMap(methodInfo.annotations().stream() .filter(ai -> ai.target().kind() == Kind.METHOD || ai.target().kind() == Kind.METHOD_PARAMETER) .collect(Collectors.toList()))); return annotationMap; } private static Map listToMap(List annotationInstances) { Map annotationMap = new HashMap<>(); for (AnnotationInstance annotationInstance : annotationInstances) { DotName name = annotationInstance.name(); annotationMap.put(name, annotationInstance); } return annotationMap; } private static Map getAnnotationsWithFilter(Type type, DotName... filter) { Map annotationMap = new HashMap<>(); if (type.kind().equals(Type.Kind.PARAMETERIZED_TYPE)) { Type typeInCollection = type.asParameterizedType().arguments().get(0); annotationMap.putAll(getAnnotationsWithFilter(typeInCollection, filter)); } else { List annotations = type.annotations(); for (AnnotationInstance annotationInstance : annotations) { if (Arrays.asList(filter).contains(annotationInstance.name())) { annotationMap.put(annotationInstance.name(), annotationInstance); } } } return annotationMap; } private static final short ZERO = 0; public static final DotName REPEATABLE = DotName.createSimple("java.lang.annotation.Repeatable"); // SmallRye Common Annotations public static final DotName BLOCKING = DotName.createSimple("io.smallrye.common.annotation.Blocking"); public static final DotName NON_BLOCKING = DotName.createSimple("io.smallrye.common.annotation.NonBlocking"); // SmallRye GraphQL Annotations (Experimental) public static final DotName TO_SCALAR = DotName.createSimple("io.smallrye.graphql.api.ToScalar"); // TODO: Remove public static final DotName ADAPT_TO_SCALAR = DotName.createSimple("io.smallrye.graphql.api.AdaptToScalar"); public static final DotName ADAPT_WITH = DotName.createSimple("io.smallrye.graphql.api.AdaptWith"); public static final DotName ERROR_CODE = DotName.createSimple("io.smallrye.graphql.api.ErrorCode"); public static final DotName DATAFETCHER = DotName.createSimple("io.smallrye.graphql.api.DataFetcher"); public static final DotName SUBCRIPTION = DotName.createSimple("io.smallrye.graphql.api.Subscription"); public static final DotName DIRECTIVE = DotName.createSimple("io.smallrye.graphql.api.Directive"); public static final DotName DEFAULT_NON_NULL = DotName.createSimple("io.smallrye.graphql.api.DefaultNonNull"); public static final DotName NULLABLE = DotName.createSimple("io.smallrye.graphql.api.Nullable"); public static final DotName KOTLIN_METADATA = DotName.createSimple("kotlin.Metadata"); // MicroProfile GraphQL Annotations public static final DotName GRAPHQL_CLIENT_API = DotName .createSimple("io.smallrye.graphql.client.typesafe.api.GraphQLClientApi"); public static final DotName QUERY = DotName.createSimple("org.eclipse.microprofile.graphql.Query"); public static final DotName MUTATION = DotName.createSimple("org.eclipse.microprofile.graphql.Mutation"); public static final DotName INPUT = DotName.createSimple("org.eclipse.microprofile.graphql.Input"); public static final DotName TYPE = DotName.createSimple("org.eclipse.microprofile.graphql.Type"); public static final DotName INTERFACE = DotName.createSimple("org.eclipse.microprofile.graphql.Interface"); public static final DotName UNION = DotName.createSimple("io.smallrye.graphql.api.Union"); public static final DotName MULTIPLE = DotName.createSimple("io.smallrye.graphql.client.typesafe.api.Multiple"); public static final DotName NESTED_PARAMETER = DotName .createSimple("io.smallrye.graphql.client.typesafe.api.NestedParameter"); public static final DotName ENUM = DotName.createSimple("org.eclipse.microprofile.graphql.Enum"); public static final DotName ID = DotName.createSimple("org.eclipse.microprofile.graphql.Id"); public static final DotName DESCRIPTION = DotName.createSimple("org.eclipse.microprofile.graphql.Description"); public static final DotName DATE_FORMAT = DotName.createSimple("org.eclipse.microprofile.graphql.DateFormat"); public static final DotName NUMBER_FORMAT = DotName.createSimple("org.eclipse.microprofile.graphql.NumberFormat"); public static final DotName DEFAULT_VALUE = DotName.createSimple("org.eclipse.microprofile.graphql.DefaultValue"); public static final DotName IGNORE = DotName.createSimple("org.eclipse.microprofile.graphql.Ignore"); public static final DotName NON_NULL = DotName.createSimple("org.eclipse.microprofile.graphql.NonNull"); public static final DotName NAME = DotName.createSimple("org.eclipse.microprofile.graphql.Name"); public static final DotName SOURCE = DotName.createSimple("org.eclipse.microprofile.graphql.Source"); // Json-B Annotations public static final String JAVAX_JSONB = "javax.json.bind.annotation."; public static final DotName JAVAX_JSONB_DATE_FORMAT = DotName.createSimple(JAVAX_JSONB + "JsonbDateFormat"); public static final DotName JAVAX_JSONB_NUMBER_FORMAT = DotName.createSimple(JAVAX_JSONB + "JsonbNumberFormat"); public static final DotName JAVAX_JSONB_PROPERTY = DotName.createSimple(JAVAX_JSONB + "JsonbProperty"); public static final DotName JAVAX_JSONB_TRANSIENT = DotName.createSimple(JAVAX_JSONB + "JsonbTransient"); public static final DotName JAVAX_JSONB_CREATOR = DotName.createSimple(JAVAX_JSONB + "JsonbCreator"); public static final DotName JAVAX_JSONB_TYPE_ADAPTER = DotName.createSimple(JAVAX_JSONB + "JsonbTypeAdapter"); public static final String JAKARTA_JSONB = "jakarta.json.bind.annotation."; public static final DotName JAKARTA_JSONB_DATE_FORMAT = DotName.createSimple(JAKARTA_JSONB + "JsonbDateFormat"); public static final DotName JAKARTA_JSONB_NUMBER_FORMAT = DotName.createSimple(JAKARTA_JSONB + "JsonbNumberFormat"); public static final DotName JAKARTA_JSONB_PROPERTY = DotName.createSimple(JAKARTA_JSONB + "JsonbProperty"); public static final DotName JAKARTA_JSONB_TRANSIENT = DotName.createSimple(JAKARTA_JSONB + "JsonbTransient"); public static final DotName JAKARTA_JSONB_CREATOR = DotName.createSimple(JAKARTA_JSONB + "JsonbCreator"); public static final DotName JAKARTA_JSONB_TYPE_ADAPTER = DotName.createSimple(JAKARTA_JSONB + "JsonbTypeAdapter"); // Jackson Annotations public static final DotName JACKSON_IGNORE = DotName.createSimple("com.fasterxml.jackson.annotation.JsonIgnore"); public static final DotName JACKSON_PROPERTY = DotName.createSimple("com.fasterxml.jackson.annotation.JsonProperty"); public static final DotName JACKSON_CREATOR = DotName.createSimple("com.fasterxml.jackson.annotation.JsonCreator"); public static final DotName JACKSON_FORMAT = DotName.createSimple("com.fasterxml.jackson.annotation.JsonFormat"); // Bean Validation Annotations (SmallRye extra, not part of the spec) public static final DotName JAVAX_BEAN_VALIDATION_NOT_NULL = DotName.createSimple("javax.validation.constraints.NotNull"); public static final DotName JAVAX_BEAN_VALIDATION_NOT_EMPTY = DotName.createSimple("javax.validation.constraints.NotEmpty"); public static final DotName JAVAX_BEAN_VALIDATION_NOT_BLANK = DotName.createSimple("javax.validation.constraints.NotBlank"); public static final DotName JAKARTA_BEAN_VALIDATION_NOT_NULL = DotName .createSimple("jakarta.validation.constraints.NotNull"); public static final DotName JAKARTA_BEAN_VALIDATION_NOT_EMPTY = DotName .createSimple("jakarta.validation.constraints.NotEmpty"); public static final DotName JAKARTA_BEAN_VALIDATION_NOT_BLANK = DotName .createSimple("jakarta.validation.constraints.NotBlank"); public static final DotName JAKARTA_NON_NULL = DotName.createSimple("jakarta.validation.constraints.NotNull"); //Kotlin NotNull public static final DotName KOTLIN_NOT_NULL = DotName.createSimple("org.jetbrains.annotations.NotNull"); }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy