AnnotatedTypeBuilder.java
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2026 Hazendaz
*/
/*
* 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 com.github.hazendaz.beanprovider.internal.deltaspike.metadata.builder;
import jakarta.enterprise.inject.spi.Annotated;
import jakarta.enterprise.inject.spi.AnnotatedConstructor;
import jakarta.enterprise.inject.spi.AnnotatedField;
import jakarta.enterprise.inject.spi.AnnotatedMethod;
import jakarta.enterprise.inject.spi.AnnotatedParameter;
import jakarta.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.util.HashMap;
import java.util.Map;
import org.apache.deltaspike.core.util.ReflectionUtils;
/**
* 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<>();
constructorParameters = new HashMap<>();
constructorParameterTypes = new HashMap<>();
fields = new HashMap<>();
fieldTypes = new HashMap<>();
methods = new HashMap<>();
methodParameters = new HashMap<>();
methodParameterTypes = new HashMap<>();
}
/**
* 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<>());
}
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<>());
}
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<>());
}
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<>());
}
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);
}
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);
}
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<>();
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<>();
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<>();
Map<Constructor<?>, AnnotationStore> constructorAnnotations = new HashMap<>();
Map<Method, Map<Integer, AnnotationStore>> methodParameterAnnotations = new HashMap<>();
Map<Method, AnnotationStore> methodAnnotations = new HashMap<>();
Map<Field, AnnotationStore> fieldAnnotations = new HashMap<>();
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<>();
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<>();
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<>());
}
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<>());
}
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;
}
}