com.atlassian.bamboo.specs.codegen.emitters.fragment.FieldSetterEmitterFactory Maven / Gradle / Ivy
package com.atlassian.bamboo.specs.codegen.emitters.fragment;
import com.atlassian.bamboo.specs.api.builders.EntityPropertiesBuilder;
import com.atlassian.bamboo.specs.api.codegen.CodeEmitter;
import com.atlassian.bamboo.specs.api.codegen.CodeGenerationContext;
import com.atlassian.bamboo.specs.api.codegen.CodeGenerationException;
import com.atlassian.bamboo.specs.api.codegen.annotations.Secret;
import com.atlassian.bamboo.specs.api.codegen.annotations.Setter;
import com.atlassian.bamboo.specs.api.model.EntityProperties;
import com.atlassian.bamboo.specs.codegen.BuilderClassProvider;
import com.atlassian.bamboo.specs.codegen.emitters.CodeGenerationUtils;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
/**
* Utility to resolve the best code generator for a field of {@link EntityProperties} instance.
*/
public final class FieldSetterEmitterFactory {
private FieldSetterEmitterFactory() {
}
private static Object getFirstElement(final Iterable value) {
return value.iterator().next(); //!called in context when we know element exists;
}
private static CodeEmitter findSetterForField(final Class builderClass,
final Field field,
final String name,
final Object value,
boolean strictNameMatch) throws CodeGenerationException {
Class type = field.getType().isPrimitive() ? field.getType() : value.getClass();
String expectedMethodName = name;
Class argumentType = type;
Class arrayElementClass = null;
if (EntityProperties.class.isAssignableFrom(type)) {
argumentType = BuilderClassProvider.findBuilderClass(type);
if (argumentType == null) {
throw new CodeGenerationException("Could not find builder for field " + field.getName() + " of class " + type.getCanonicalName());
}
if (!strictNameMatch) {
expectedMethodName = expectedMethodName.replace("Properties", "");
}
} else if (Iterable.class.isAssignableFrom(argumentType)) {
arrayElementClass = getFirstElement((Iterable) value).getClass();
if (EntityProperties.class.isAssignableFrom(arrayElementClass)) {
arrayElementClass = BuilderClassProvider.findBuilderClass(arrayElementClass);
}
}
int matchingMethodCount = 0;
Method candidateMethod = null;
for (Method method : builderClass.getMethods()) {
if (method.getDeclaringClass() == Object.class) {
continue; //we don't want any equals an the likes
}
if (method.getParameters().length == 1) {
final Parameter parameter = method.getParameters()[0];
if (expectedMethodName.equals(method.getName()) && isAssignableToParameterType(argumentType, parameter)) {
return createFieldSetterEmitter(field, method);
}
if (expectedMethodName.equals(method.getName()) && Iterable.class.isAssignableFrom(argumentType)) {
if (parameter.getType().isArray()) {
if (parameter.getType().getComponentType().isAssignableFrom(arrayElementClass)) {
return new VarargArgumentSetterEmitter(method.getName());
} else {
continue;
}
}
} else if (!strictNameMatch && EntityPropertiesBuilder.class.isAssignableFrom(argumentType) && isAssignableToParameterType(argumentType, parameter)) {
//for bamboo entity classes only: if we find exact argument match and there's only one such method, this is it
matchingMethodCount++;
candidateMethod = method;
} else if (!strictNameMatch && StringUtils.containsIgnoreCase(method.getName(), name) && isAssignableToParameterType(argumentType, parameter)) {
//name looks sort of correct...
matchingMethodCount++;
candidateMethod = method;
}
}
}
if (matchingMethodCount == 1) {
return createFieldSetterEmitter(field, candidateMethod);
}
throw new CodeGenerationException("Could not find suitable setter for field " + field.getName() + " expected method called " + expectedMethodName);
}
private static CodeEmitter createFieldSetterEmitter(Field field, Method method) {
return field.isAnnotationPresent(Secret.class) ?
new SecretSetterEmitter(method.getName())
:
new FieldSetterEmitter(method.getName());
}
private static boolean isAssignableToParameterType(Class valueType, Parameter parameter) {
Class parameterType = parameter.getType();
if (parameterType.isAssignableFrom(valueType)) {
return true;
}
if (parameterType == Boolean.class && valueType == Boolean.TYPE) {
return true;
}
if (parameterType == Long.class && valueType == Long.TYPE) {
return true;
}
if (parameterType == Integer.class && valueType == Integer.TYPE) {
return true;
}
return false;
}
public static CodeEmitter fieldSetterEmitterFor(final CodeGenerationContext context,
final Class builderClass,
final Field field,
final Object fieldValue) throws CodeGenerationException {
CodeEmitter codeEmitter = CodeGenerationUtils.findEmitterByAnnotation(field);
if (codeEmitter != null) {
return codeEmitter;
} else if (field.isAnnotationPresent(Setter.class)) {
String setterName = field.getAnnotation(Setter.class).value();
return findSetterForField(builderClass, field, setterName, fieldValue, true);
}
return findSetterForField(builderClass, field, field.getName(), fieldValue, false);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy