in johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/BaseAccessMode.java [119:269]
public Factory findFactory(final Class<?> clazz, final Function<AnnotatedElement, String>... parameterNameExtractors) {
Constructor<?> constructor = null;
final boolean record = isRecord(clazz);
if (record || Meta.getAnnotation(clazz, JohnzonRecord.class) != null) {
constructor = findRecordConstructor(clazz);
} else {
for (final Constructor<?> c : clazz.getDeclaredConstructors()) {
if (c.getParameterTypes().length == 0) {
if (!Modifier.isPublic(c.getModifiers()) && acceptHiddenConstructor) {
c.setAccessible(true);
}
constructor = c;
if (!useConstructor) {
break;
}
} else if (c.getAnnotation(ConstructorProperties.class) != null) {
constructor = c;
break;
}
}
if (constructor == null) {
try {
constructor = clazz.getConstructor();
} catch (final NoSuchMethodException e) {
return null; // readOnly class
}
}
}
final boolean constructorHasArguments = constructor != null && constructor.getGenericParameterTypes().length > 0;
final Type[] factoryParameterTypes;
final String[] constructorParameters;
final Adapter<?, ?>[] constructorParameterConverters;
final Adapter<?, ?>[] constructorItemParameterConverters;
final ObjectConverter.Codec<?>[] objectConverters;
if (constructorHasArguments) {
factoryParameterTypes = constructor.getGenericParameterTypes();
constructorParameters = new String[constructor.getGenericParameterTypes().length];
final Constructor<?> fc = constructor;
final String[] constructorProperties = ofNullable(constructor.getAnnotation(ConstructorProperties.class))
.map(ConstructorProperties::value)
.orElseGet(() -> {
if (record) {
return Stream.of(fc.getParameters())
.map(p -> {
try {
if (parameterNameExtractors != null) {
return Stream.of(parameterNameExtractors)
.map(fn -> fn.apply(p))
.filter(Objects::nonNull)
.findFirst()
.orElseGet(p::getName);
}
final JohnzonProperty property = Meta.getAnnotation(
clazz.getMethod(p.getName()), JohnzonProperty.class);
return property != null ? property.value() : p.getName();
} catch (final NoSuchMethodException e) {
return p.getName();
}
})
.toArray(String[]::new);
}
return Stream.of(fc.getParameters())
.map(p -> ofNullable(p.getAnnotation(JohnzonRecord.Name.class))
.map(JohnzonRecord.Name::value)
.orElseGet(p::getName))
.toArray(String[]::new);
});
System.arraycopy(constructorProperties, 0, constructorParameters, 0, constructorParameters.length);
constructorParameterConverters = new Adapter<?, ?>[constructor.getGenericParameterTypes().length];
constructorItemParameterConverters = new Adapter<?, ?>[constructorParameterConverters.length];
objectConverters = new ObjectConverter.Codec[constructorParameterConverters.length];
for (int i = 0; i < constructorParameters.length; i++) {
for (final Annotation a : constructor.getParameterAnnotations()[i]) {
if (a.annotationType() == JohnzonConverter.class) {
try {
MapperConverter mapperConverter = JohnzonConverter.class.cast(a).value().newInstance();
if (mapperConverter instanceof Converter) {
final Adapter<?, ?> converter = new ConverterAdapter((Converter) mapperConverter, constructor.getGenericParameterTypes()[i]);
if (matches(constructor.getParameterTypes()[i], converter)) {
constructorParameterConverters[i] = converter;
constructorItemParameterConverters[i] = null;
} else {
constructorParameterConverters[i] = null;
constructorItemParameterConverters[i] = converter;
}
} else {
objectConverters[i] = (ObjectConverter.Codec<?>) mapperConverter;
}
} catch (final Exception e) {
throw new IllegalArgumentException(e);
}
}
}
}
} else {
factoryParameterTypes = NO_PARAMS;
constructorParameters = null;
constructorParameterConverters = null;
constructorItemParameterConverters = null;
objectConverters = null;
}
final Constructor<?> cons = constructor;
if (cons != null && !cons.isAccessible()) {
cons.setAccessible(true);
}
return new Factory() {
@Override
public Object create(final Object[] params) {
if (cons == null) {
throw new IllegalArgumentException(clazz.getName() + " can't be instantiated by Johnzon, this is a write only class");
}
try {
return params == null ? cons.newInstance() : cons.newInstance(params);
} catch (final InstantiationException | IllegalAccessException e) {
throw new IllegalStateException(e);
} catch (final InvocationTargetException e) {
throw new IllegalStateException(e.getCause());
}
}
@Override
public Type[] getParameterTypes() {
return factoryParameterTypes;
}
@Override
public String[] getParameterNames() {
return constructorParameters;
}
@Override
public Adapter<?, ?>[] getParameterConverter() {
return constructorParameterConverters;
}
@Override
public Adapter<?, ?>[] getParameterItemConverter() {
return constructorItemParameterConverters;
}
@Override
public ObjectConverter.Codec<?>[] getObjectConverter() {
return objectConverters;
}
};
}