/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.deltaspike.core.util.metadata.builder; import org.apache.deltaspike.core.util.ReflectionUtils; import org.apache.deltaspike.core.util.securitymanaged.SetAccessiblePrivilegedAction; import javax.enterprise.inject.spi.Annotated; import javax.enterprise.inject.spi.AnnotatedConstructor; import javax.enterprise.inject.spi.AnnotatedField; import javax.enterprise.inject.spi.AnnotatedMethod; import javax.enterprise.inject.spi.AnnotatedParameter; import javax.enterprise.inject.spi.AnnotatedType; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.security.AccessController; import java.util.HashMap; import java.util.Map; /** * Builder to aid in creation of a new {@link AnnotatedType} for use in CDI life cycle events. * Using the builder is typically done by reading the annotations from a {@link Class} or an * {@link AnnotatedType}. Once the starting class or type has been added all of annotations * can be modified: constructor, parameter, class, method and fields. * <p/> * The AnnotatedTypeBuilder is not thread safe and shall not be used concurrently! */ public class AnnotatedTypeBuilder<X> { private Class<X> javaClass; private final AnnotationBuilder typeAnnotations; private final Map<Constructor<?>, AnnotationBuilder> constructors; private final Map<Constructor<?>, Map<Integer, AnnotationBuilder>> constructorParameters; private final Map<Constructor<?>, Map<Integer, Type>> constructorParameterTypes; private final Map<Field, AnnotationBuilder> fields; private final Map<Field, Type> fieldTypes; private final Map<Method, AnnotationBuilder> methods; private final Map<Method, Map<Integer, AnnotationBuilder>> methodParameters; private final Map<Method, Map<Integer, Type>> methodParameterTypes; /** * Create a new builder. A new builder has no annotations and no members. * * @see #readFromType(AnnotatedType) * @see #readFromType(Class) * @see #readFromType(AnnotatedType, boolean) * @see #readFromType(Class, boolean) */ public AnnotatedTypeBuilder() { typeAnnotations = new AnnotationBuilder(); constructors = new HashMap<Constructor<?>, AnnotationBuilder>(); constructorParameters = new HashMap<Constructor<?>, Map<Integer, AnnotationBuilder>>(); constructorParameterTypes = new HashMap<Constructor<?>, Map<Integer, Type>>(); fields = new HashMap<Field, AnnotationBuilder>(); fieldTypes = new HashMap<Field, Type>(); methods = new HashMap<Method, AnnotationBuilder>(); methodParameters = new HashMap<Method, Map<Integer, AnnotationBuilder>>(); methodParameterTypes = new HashMap<Method, Map<Integer, Type>>(); } /** * Add an annotation to the type declaration. * * @param annotation the annotation instance to add * @throws IllegalArgumentException if the annotation is null */ public AnnotatedTypeBuilder<X> addToClass(Annotation annotation) { typeAnnotations.add(annotation); return this; } /** * Remove an annotation from the type * * @param annotationType the annotation type to remove * @throws IllegalArgumentException if the annotationType */ public AnnotatedTypeBuilder<X> removeFromClass(Class<? extends Annotation> annotationType) { typeAnnotations.remove(annotationType); return this; } /** * Add an annotation to the specified field. If the field is not already * present, it will be added. * * @param field the field to add the annotation to * @param annotation the annotation to add * @throws IllegalArgumentException if the annotation is null */ public AnnotatedTypeBuilder<X> addToField(Field field, Annotation annotation) { if (fields.get(field) == null) { fields.put(field, new AnnotationBuilder()); } fields.get(field).add(annotation); return this; } /** * Add an annotation to the specified field. If the field is not already * present, it will be added. * * @param field the field to add the annotation to * @param annotation the annotation to add * @throws IllegalArgumentException if the annotation is null */ public AnnotatedTypeBuilder<X> addToField(AnnotatedField<? super X> field, Annotation annotation) { return addToField(field.getJavaMember(), annotation); } /** * Remove an annotation from the specified field. * * @param field the field to remove the annotation from * @param annotationType the annotation type to remove * @throws IllegalArgumentException if the annotationType is null or if the * field is not currently declared on the type */ public AnnotatedTypeBuilder<X> removeFromField(Field field, Class<? extends Annotation> annotationType) { if (fields.get(field) == null) { throw new IllegalArgumentException("field " + field + " not present on class " + getJavaClass()); } else { fields.get(field).remove(annotationType); } return this; } /** * Remove an annotation from the specified field. * * @param field the field to remove the annotation from * @param annotationType the annotation type to remove * @throws IllegalArgumentException if the annotationType is null or if the * field is not currently declared on the type */ public AnnotatedTypeBuilder<X> removeFromField(AnnotatedField<? super X> field, Class<? extends Annotation> annotationType) { return removeFromField(field.getJavaMember(), annotationType); } /** * Add an annotation to the specified method. If the method is not already * present, it will be added. * * @param method the method to add the annotation to * @param annotation the annotation to add * @throws IllegalArgumentException if the annotation is null */ public AnnotatedTypeBuilder<X> addToMethod(Method method, Annotation annotation) { if (methods.get(method) == null) { methods.put(method, new AnnotationBuilder()); } methods.get(method).add(annotation); return this; } /** * Add an annotation to the specified method. If the method is not already * present, it will be added. * * @param method the method to add the annotation to * @param annotation the annotation to add * @throws IllegalArgumentException if the annotation is null */ public AnnotatedTypeBuilder<X> addToMethod(AnnotatedMethod<? super X> method, Annotation annotation) { return addToMethod(method.getJavaMember(), annotation); } /** * Remove an annotation from the specified method. * * @param method the method to remove the annotation from * @param annotationType the annotation type to remove * @throws IllegalArgumentException if the annotationType is null or if the * method is not currently declared on the type */ public AnnotatedTypeBuilder<X> removeFromMethod(Method method, Class<? extends Annotation> annotationType) { if (methods.get(method) == null) { throw new IllegalArgumentException("Method " + method + " not present on class" + getJavaClass()); } else { methods.get(method).remove(annotationType); } return this; } /** * Remove an annotation from the specified method. * * @param method the method to remove the annotation from * @param annotationType the annotation type to remove * @throws IllegalArgumentException if the annotationType is null or if the * method is not currently declared on the type */ public AnnotatedTypeBuilder<X> removeFromMethod(AnnotatedMethod<? super X> method, Class<? extends Annotation> annotationType) { return removeFromMethod(method.getJavaMember(), annotationType); } /** * Add an annotation to the specified method parameter. If the method is not * already present, it will be added. If the method parameter is not already * present, it will be added. * * @param method the method to add the annotation to * @param position the position of the parameter to add * @param annotation the annotation to add * @throws IllegalArgumentException if the annotation is null */ public AnnotatedTypeBuilder<X> addToMethodParameter(Method method, int position, Annotation annotation) { if (!methods.containsKey(method)) { methods.put(method, new AnnotationBuilder()); } if (methodParameters.get(method) == null) { methodParameters.put(method, new HashMap<Integer, AnnotationBuilder>()); } if (methodParameters.get(method).get(position) == null) { methodParameters.get(method).put(position, new AnnotationBuilder()); } methodParameters.get(method).get(position).add(annotation); return this; } /** * Remove an annotation from the specified method parameter. * * @param method the method to remove the annotation from * @param position the position of the parameter to remove * @param annotationType the annotation type to remove * @throws IllegalArgumentException if the annotationType is null, if the * method is not currently declared on the type or if the * parameter is not declared on the method */ public AnnotatedTypeBuilder<X> removeFromMethodParameter(Method method, int position, Class<? extends Annotation> annotationType) { if (methods.get(method) == null) { throw new IllegalArgumentException("Method " + method + " not present on class " + getJavaClass()); } else { if (methodParameters.get(method).get(position) == null) { throw new IllegalArgumentException( String.format("parameter %s not present on method %s declared on class %s", method, position, getJavaClass())); } else { methodParameters.get(method).get(position).remove(annotationType); } } return this; } /** * Add an annotation to the specified constructor. If the constructor is not * already present, it will be added. * * @param constructor the constructor to add the annotation to * @param annotation the annotation to add * @throws IllegalArgumentException if the annotation is null */ public AnnotatedTypeBuilder<X> addToConstructor(Constructor<X> constructor, Annotation annotation) { if (constructors.get(constructor) == null) { constructors.put(constructor, new AnnotationBuilder()); } constructors.get(constructor).add(annotation); return this; } /** * Add an annotation to the specified constructor. If the constructor is not * already present, it will be added. * * @param constructor the constructor to add the annotation to * @param annotation the annotation to add * @throws IllegalArgumentException if the annotation is null */ public AnnotatedTypeBuilder<X> addToConstructor(AnnotatedConstructor<X> constructor, Annotation annotation) { return addToConstructor(constructor.getJavaMember(), annotation); } /** * Remove an annotation from the specified constructor. * * @param constructor the constructor to add the annotation to * @param annotationType the annotation to add * @throws IllegalArgumentException if the annotationType is null or if the * constructor is not currently declared on the type */ public AnnotatedTypeBuilder<X> removeFromConstructor(Constructor<X> constructor, Class<? extends Annotation> annotationType) { if (constructors.get(constructor) != null) { constructors.get(constructor).remove(annotationType); } return this; } /** * Remove an annotation from the specified constructor. * * @param constructor the constructor to add the annotation to * @param annotationType the annotation to add * @throws IllegalArgumentException if the annotationType is null, if the * annotation does not exist on the type or if the constructor is * not currently declared on the type */ public AnnotatedTypeBuilder<X> removeFromConstructor(AnnotatedConstructor<X> constructor, Class<? extends Annotation> annotationType) { return removeFromConstructor(constructor.getJavaMember(), annotationType); } /** * Add an annotation to the specified constructor parameter. If the * constructor is not already present, it will be added. If the constructor * parameter is not already present, it will be added. * * @param constructor the constructor to add the annotation to * @param position the position of the parameter to add * @param annotation the annotation to add * @throws IllegalArgumentException if the annotation is null */ public AnnotatedTypeBuilder<X> addToConstructorParameter(Constructor<X> constructor, int position, Annotation annotation) { if (!constructors.containsKey(constructor)) { constructors.put(constructor, new AnnotationBuilder()); } if (constructorParameters.get(constructor) == null) { constructorParameters.put(constructor, new HashMap<Integer, AnnotationBuilder>()); } if (constructorParameters.get(constructor).get(position) == null) { constructorParameters.get(constructor).put(position, new AnnotationBuilder()); } constructorParameters.get(constructor).get(position).add(annotation); return this; } /** * Remove an annotation from the specified constructor parameter. * * @param constructor the constructor to remove the annotation from * @param position the position of the parameter to remove * @param annotationType the annotation type to remove * @throws IllegalArgumentException if the annotationType is null, if the * constructor is not currently declared on the type or if the * parameter is not declared on the constructor */ public AnnotatedTypeBuilder<X> removeFromConstructorParameter(Constructor<X> constructor, int position, Class<? extends Annotation> annotationType) { if (constructorParameters.get(constructor) != null && constructorParameters.get(constructor).get(position) != null) { constructorParameters.get(constructor).get(position).remove(annotationType); } return this; } /** * Remove an annotation from the specified parameter. * * @param parameter the parameter to remove the annotation from * @param annotationType the annotation type to remove * @throws IllegalArgumentException if the annotationType is null, if the * callable which declares the parameter is not currently declared * on the type or if the parameter is not declared on either a * constructor or a method */ public AnnotatedTypeBuilder<X> removeFromParameter(AnnotatedParameter<? super X> parameter, Class<? extends Annotation> annotationType) { if (parameter.getDeclaringCallable().getJavaMember() instanceof Method) { Method method = (Method) parameter.getDeclaringCallable().getJavaMember(); return removeFromMethodParameter(method, parameter.getPosition(), annotationType); } if (parameter.getDeclaringCallable().getJavaMember() instanceof Constructor<?>) { @SuppressWarnings("unchecked") Constructor<X> constructor = (Constructor<X>) parameter.getDeclaringCallable().getJavaMember(); return removeFromConstructorParameter(constructor, parameter.getPosition(), annotationType); } else { throw new IllegalArgumentException("Cannot remove from parameter " + parameter + " - cannot operate on member " + parameter.getDeclaringCallable().getJavaMember()); } } /** * Add an annotation to the specified parameter. If the callable which * declares the parameter is not already present, it will be added. If the * parameter is not already present on the callable, it will be added. * * @param parameter the parameter to add the annotation to * @param annotation the annotation to add * @throws IllegalArgumentException if the annotation is null or if the * parameter is not declared on either a constructor or a method */ public AnnotatedTypeBuilder<X> addToParameter(AnnotatedParameter<? super X> parameter, Annotation annotation) { if (parameter.getDeclaringCallable().getJavaMember() instanceof Method) { Method method = (Method) parameter.getDeclaringCallable().getJavaMember(); return addToMethodParameter(method, parameter.getPosition(), annotation); } if (parameter.getDeclaringCallable().getJavaMember() instanceof Constructor<?>) { @SuppressWarnings("unchecked") Constructor<X> constructor = (Constructor<X>) parameter.getDeclaringCallable().getJavaMember(); return addToConstructorParameter(constructor, parameter.getPosition(), annotation); } else { throw new IllegalArgumentException("Cannot remove from parameter " + parameter + " - cannot operate on member " + parameter.getDeclaringCallable().getJavaMember()); } } /** * Remove annotations from the type, and all of it's members. If an * annotation of the specified type appears on the type declaration, or any * of it's members it will be removed. * * @param annotationType the type of annotation to remove * @throws IllegalArgumentException if the annotationType is null */ public AnnotatedTypeBuilder<X> removeFromAll(Class<? extends Annotation> annotationType) { if (annotationType == null) { throw new IllegalArgumentException(String.format("%s parameter must not be null", "annotationType")); } removeFromClass(annotationType); for (Map.Entry<Field, AnnotationBuilder> field : fields.entrySet()) { field.getValue().remove(annotationType); } for (Map.Entry<Method, AnnotationBuilder> method : methods.entrySet()) { method.getValue().remove(annotationType); if (methodParameters.get(method.getKey()) != null) { for (Map.Entry<Integer, AnnotationBuilder> parameter : methodParameters.get(method.getKey()).entrySet()) { parameter.getValue().remove(annotationType); } } } for (Map.Entry<Constructor<?>, AnnotationBuilder> constructor : constructors.entrySet()) { constructor.getValue().remove(annotationType); if (constructorParameters.get(constructor.getKey()) != null) { for (Map.Entry<Integer, AnnotationBuilder> parameter : constructorParameters.get(constructor.getKey()).entrySet()) { parameter.getValue().remove(annotationType); } } } return this; } /** * Reads in from an existing AnnotatedType. Any elements not present are * added. The javaClass will be read in. If the annotation already exists on * that element in the builder the read annotation will be used. * * @param type the type to read from * @throws IllegalArgumentException if type is null */ public AnnotatedTypeBuilder<X> readFromType(AnnotatedType<X> type) { return readFromType(type, true); } /** * Reads in from an existing AnnotatedType. Any elements not present are * added. The javaClass will be read in if overwrite is true. If the * annotation already exists on that element in the builder, overwrite * determines whether the original or read annotation will be used. * * @param type the type to read from * @param overwrite if true, the read annotation will replace any existing * annotation * @throws IllegalArgumentException if type is null */ public AnnotatedTypeBuilder<X> readFromType(AnnotatedType<X> type, boolean overwrite) { if (type == null) { throw new IllegalArgumentException(String.format("%s parameter must not be null", "type")); } if (javaClass == null || overwrite) { javaClass = type.getJavaClass(); } mergeAnnotationsOnElement(type, overwrite, typeAnnotations); for (AnnotatedField<? super X> field : type.getFields()) { if (fields.get(field.getJavaMember()) == null) { fields.put(field.getJavaMember(), new AnnotationBuilder()); } mergeAnnotationsOnElement(field, overwrite, fields.get(field.getJavaMember())); } for (AnnotatedMethod<? super X> method : type.getMethods()) { if (methods.get(method.getJavaMember()) == null) { methods.put(method.getJavaMember(), new AnnotationBuilder()); } mergeAnnotationsOnElement(method, overwrite, methods.get(method.getJavaMember())); for (AnnotatedParameter<? super X> p : method.getParameters()) { if (methodParameters.get(method.getJavaMember()) == null) { methodParameters.put(method.getJavaMember(), new HashMap<Integer, AnnotationBuilder>()); } if (methodParameters.get(method.getJavaMember()).get(p.getPosition()) == null) { methodParameters.get(method.getJavaMember()).put(p.getPosition(), new AnnotationBuilder()); } mergeAnnotationsOnElement( p, overwrite, methodParameters.get(method.getJavaMember()).get(p.getPosition())); } } for (AnnotatedConstructor<? super X> constructor : type.getConstructors()) { if (constructors.get(constructor.getJavaMember()) == null) { constructors.put(constructor.getJavaMember(), new AnnotationBuilder()); } mergeAnnotationsOnElement(constructor, overwrite, constructors.get(constructor.getJavaMember())); for (AnnotatedParameter<? super X> p : constructor.getParameters()) { if (constructorParameters.get( constructor.getJavaMember()) == null) { constructorParameters.put( constructor.getJavaMember(), new HashMap<Integer, AnnotationBuilder>()); } if (constructorParameters.get( constructor.getJavaMember()).get(p.getPosition()) == null) { constructorParameters.get( constructor.getJavaMember()).put(p.getPosition(), new AnnotationBuilder()); } mergeAnnotationsOnElement( p, overwrite, constructorParameters.get(constructor.getJavaMember()).get(p.getPosition())); } } return this; } /** * Reads the annotations from an existing java type. Annotations already * present will be overwritten * * @param type the type to read from * @throws IllegalArgumentException if type is null */ public AnnotatedTypeBuilder<X> readFromType(Class<X> type) { return readFromType(type, true); } /** * Reads the annotations from an existing java type. If overwrite is true * then existing annotations will be overwritten * * @param type the type to read from * @param overwrite if true, the read annotation will replace any existing * annotation */ public AnnotatedTypeBuilder<X> readFromType(Class<X> type, boolean overwrite) { if (type == null) { throw new IllegalArgumentException(String.format("%s parameter must not be null", "type")); } if (javaClass == null || overwrite) { javaClass = type; } for (Annotation annotation : type.getAnnotations()) { if (overwrite || !typeAnnotations.isAnnotationPresent(annotation.annotationType())) { typeAnnotations.add(annotation); } } for (Field field : ReflectionUtils.getAllDeclaredFields(type)) { AnnotationBuilder annotationBuilder = fields.get(field); if (annotationBuilder == null) { annotationBuilder = new AnnotationBuilder(); fields.put(field, annotationBuilder); } if (System.getSecurityManager() != null) { AccessController.doPrivileged(new SetAccessiblePrivilegedAction(field)); } else { field.setAccessible(true); } for (Annotation annotation : field.getAnnotations()) { if (overwrite || !annotationBuilder.isAnnotationPresent(annotation.annotationType())) { annotationBuilder.add(annotation); } } } for (Method method : ReflectionUtils.getAllDeclaredMethods(type)) { AnnotationBuilder annotationBuilder = methods.get(method); if (annotationBuilder == null) { annotationBuilder = new AnnotationBuilder(); methods.put(method, annotationBuilder); } if (System.getSecurityManager() != null) { AccessController.doPrivileged(new SetAccessiblePrivilegedAction(method)); } else { method.setAccessible(true); } for (Annotation annotation : method.getAnnotations()) { if (overwrite || !annotationBuilder.isAnnotationPresent(annotation.annotationType())) { annotationBuilder.add(annotation); } } Map<Integer, AnnotationBuilder> parameters = methodParameters.get(method); if (parameters == null) { parameters = new HashMap<Integer, AnnotationBuilder>(); methodParameters.put(method, parameters); } for (int i = 0; i < method.getParameterTypes().length; ++i) { AnnotationBuilder parameterAnnotationBuilder = parameters.get(i); if (parameterAnnotationBuilder == null) { parameterAnnotationBuilder = new AnnotationBuilder(); parameters.put(i, parameterAnnotationBuilder); } for (Annotation annotation : method.getParameterAnnotations()[i]) { if (overwrite || !parameterAnnotationBuilder.isAnnotationPresent(annotation.annotationType())) { parameterAnnotationBuilder.add(annotation); } } } } for (Constructor<?> constructor : type.getDeclaredConstructors()) { AnnotationBuilder annotationBuilder = constructors.get(constructor); if (annotationBuilder == null) { annotationBuilder = new AnnotationBuilder(); constructors.put(constructor, annotationBuilder); } constructor.setAccessible(true); for (Annotation annotation : constructor.getAnnotations()) { if (overwrite || !annotationBuilder.isAnnotationPresent(annotation.annotationType())) { annotationBuilder.add(annotation); } } Map<Integer, AnnotationBuilder> mparams = constructorParameters.get(constructor); if (mparams == null) { mparams = new HashMap<Integer, AnnotationBuilder>(); constructorParameters.put(constructor, mparams); } for (int i = 0; i < constructor.getParameterTypes().length; ++i) { AnnotationBuilder parameterAnnotationBuilder = mparams.get(i); if (parameterAnnotationBuilder == null) { parameterAnnotationBuilder = new AnnotationBuilder(); mparams.put(i, parameterAnnotationBuilder); } for (Annotation annotation : constructor.getParameterAnnotations()[i]) { if (overwrite || !parameterAnnotationBuilder.isAnnotationPresent(annotation.annotationType())) { annotationBuilder.add(annotation); } } } } return this; } protected void mergeAnnotationsOnElement(Annotated annotated, boolean overwriteExisting, AnnotationBuilder typeAnnotations) { for (Annotation annotation : annotated.getAnnotations()) { if (typeAnnotations.getAnnotation(annotation.annotationType()) != null) { if (overwriteExisting) { typeAnnotations.remove(annotation.annotationType()); typeAnnotations.add(annotation); } } else { typeAnnotations.add(annotation); } } } /** * Create an {@link AnnotatedType}. Any public members present on the * underlying class and not overridden by the builder will be automatically * added. */ public AnnotatedType<X> create() { Map<Constructor<?>, Map<Integer, AnnotationStore>> constructorParameterAnnotations = new HashMap<Constructor<?>, Map<Integer, AnnotationStore>>(); Map<Constructor<?>, AnnotationStore> constructorAnnotations = new HashMap<Constructor<?>, AnnotationStore>(); Map<Method, Map<Integer, AnnotationStore>> methodParameterAnnotations = new HashMap<Method, Map<Integer, AnnotationStore>>(); Map<Method, AnnotationStore> methodAnnotations = new HashMap<Method, AnnotationStore>(); Map<Field, AnnotationStore> fieldAnnotations = new HashMap<Field, AnnotationStore>(); for (Map.Entry<Field, AnnotationBuilder> field : fields.entrySet()) { fieldAnnotations.put(field.getKey(), field.getValue().create()); } for (Map.Entry<Method, AnnotationBuilder> method : methods.entrySet()) { methodAnnotations.put(method.getKey(), method.getValue().create()); } for (Map.Entry<Method, Map<Integer, AnnotationBuilder>> parameters : methodParameters.entrySet()) { Map<Integer, AnnotationStore> parameterAnnotations = new HashMap<Integer, AnnotationStore>(); methodParameterAnnotations.put(parameters.getKey(), parameterAnnotations); for (Map.Entry<Integer, AnnotationBuilder> parameter : parameters.getValue().entrySet()) { parameterAnnotations.put(parameter.getKey(), parameter.getValue().create()); } } for (Map.Entry<Constructor<?>, AnnotationBuilder> constructor : constructors.entrySet()) { constructorAnnotations.put(constructor.getKey(), constructor.getValue().create()); } for (Map.Entry<Constructor<?>, Map<Integer, AnnotationBuilder>> parameters : constructorParameters.entrySet()) { Map<Integer, AnnotationStore> parameterAnnotations = new HashMap<Integer, AnnotationStore>(); constructorParameterAnnotations.put(parameters.getKey(), parameterAnnotations); for (Map.Entry<Integer, AnnotationBuilder> parameter : parameters.getValue().entrySet()) { parameterAnnotations.put(parameter.getKey(), parameter.getValue().create()); } } return new AnnotatedTypeImpl<X>(javaClass, typeAnnotations.create(), fieldAnnotations, methodAnnotations, methodParameterAnnotations, constructorAnnotations, constructorParameterAnnotations, fieldTypes, methodParameterTypes, constructorParameterTypes); } /** * Override the declared type of a field * * @param field the field to override the type on * @param type the new type of the field * @throws IllegalArgumentException if field or type is null */ public void overrideFieldType(Field field, Type type) { if (field == null) { throw new IllegalArgumentException(String.format("%s parameter must not be null", "field")); } if (type == null) { throw new IllegalArgumentException(String.format("%s parameter must not be null", "type")); } fieldTypes.put(field, type); } /** * Override the declared type of a field * * @param field the field to override the type on * @param type the new type of the field * @throws IllegalArgumentException if field or type is null */ public void overrideFieldType(AnnotatedField<? super X> field, Type type) { overrideFieldType(field.getJavaMember(), type); } /** * Override the declared type of a method parameter * * @param method the method to override the parameter type on * @param position the position of the parameter to override the type on * @param type the new type of the parameter * @throws IllegalArgumentException if parameter or type is null */ public AnnotatedTypeBuilder<X> overrideMethodParameterType(Method method, int position, Type type) { if (method == null) { throw new IllegalArgumentException(String.format("%s parameter must not be null", "method")); } if (type == null) { throw new IllegalArgumentException(String.format("%s parameter must not be null", "type")); } if (methodParameterTypes.get(method) == null) { methodParameterTypes.put(method, new HashMap<Integer, Type>()); } methodParameterTypes.get(method).put(position, type); return this; } /** * Override the declared type of a constructor parameter * * @param constructor the constructor to override the parameter type on * @param position the position of the parameter to override the type on * @param type the new type of the parameter * @throws IllegalArgumentException if parameter or type is null */ public AnnotatedTypeBuilder<X> overrideConstructorParameterType(Constructor<X> constructor, int position, Type type) { if (constructor == null) { throw new IllegalArgumentException(String.format("%s parameter must not be null", "constructor")); } if (type == null) { throw new IllegalArgumentException(String.format("%s parameter must not be null", "type")); } if (constructorParameterTypes.get(constructor) == null) { constructorParameterTypes.put(constructor, new HashMap<Integer, Type>()); } constructorParameterTypes.get(constructor).put(position, type); return this; } /** * Override the declared type of a parameter. * * @param parameter the parameter to override the type on * @param type the new type of the parameter * @throws IllegalArgumentException if parameter or type is null */ public AnnotatedTypeBuilder<X> overrideParameterType(AnnotatedParameter<? super X> parameter, Type type) { if (parameter.getDeclaringCallable().getJavaMember() instanceof Method) { Method method = (Method) parameter.getDeclaringCallable().getJavaMember(); return overrideMethodParameterType(method, parameter.getPosition(), type); } if (parameter.getDeclaringCallable().getJavaMember() instanceof Constructor<?>) { @SuppressWarnings("unchecked") Constructor<X> constructor = (Constructor<X>) parameter.getDeclaringCallable().getJavaMember(); return overrideConstructorParameterType(constructor, parameter.getPosition(), type); } else { throw new IllegalArgumentException("Cannot remove from parameter " + parameter + " - cannot operate on member " + parameter.getDeclaringCallable().getJavaMember()); } } /** * getter for the class */ public Class<X> getJavaClass() { return javaClass; } /** * setter for the class */ public AnnotatedTypeBuilder<X> setJavaClass(Class<X> javaClass) { this.javaClass = javaClass; return this; } }