use of io.norberg.automatter.AutoMatter in project auto-matter by danielnorberg.
the class AutoMatterProcessor method process.
@Override
public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment env) {
final Set<TypeElement> elements = new LinkedHashSet<>();
// Enqueue new elements for processing
env.getElementsAnnotatedWith(AutoMatter.class).stream().filter(e -> e instanceof TypeElement).forEach(e -> elements.add((TypeElement) e));
// Enqueue deferred elements for processing
final List<Name> previousDeferredTypes = new ArrayList<>(deferredTypes);
deferredTypes.clear();
for (Name deferredType : previousDeferredTypes) {
final TypeElement deferredTypeElement = processingEnv.getElementUtils().getTypeElement(deferredType);
if (deferredTypeElement == null) {
deferredTypes.add(deferredType);
} else {
elements.add(deferredTypeElement);
}
}
// Process elements and generate files
for (TypeElement element : elements) {
try {
final Descriptor descriptor = process(element);
processedTypes.put(element.getQualifiedName(), descriptor);
} catch (UnresolvedTypeException e) {
// Encountered an unresolved type while processing this type, defer it for a
// later processing in hope that the type can be resolved in a later round.
deferredTypes.add(element.getQualifiedName());
} catch (AutoMatterProcessorException e) {
e.print(messager);
} catch (Exception e) {
messager.printMessage(ERROR, e.getMessage());
}
}
if (env.processingOver()) {
// This was the last round, complain if some types failed due to unresolved types
for (Name deferredType : deferredTypes) {
final TypeElement deferredTypeElement = processingEnv.getElementUtils().getTypeElement(deferredType);
messager.printMessage(ERROR, "Failed to generate @AutoMatter builder for " + deferredType + " because some fields have unresolved types", deferredTypeElement);
}
// Perform validation that can only be done after processing has been completed
for (Descriptor descriptor : processedTypes.values()) {
try {
validate(descriptor);
} catch (AutoMatterProcessorException e) {
e.print(messager);
} catch (Exception e) {
messager.printMessage(ERROR, e.getMessage());
}
}
}
return false;
}
use of io.norberg.automatter.AutoMatter in project auto-matter by danielnorberg.
the class AutoMatterTypeAdapterFactory method create.
@SuppressWarnings("unchecked")
@Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {
final TypeAdapter<T> materialized;
final AutoMatter annotation = type.getRawType().getAnnotation(AutoMatter.class);
if (annotation != null) {
if (!type.getRawType().isInterface()) {
// Only handle interface style @AutoMatter types.
return null;
}
// We are now the proud owners of an AutoMatter annotated interface.
// Return the cached type, if present.
final TypeAdapter<T> cached = (TypeAdapter<T>) adapters.get(type);
if (cached != null) {
return cached;
}
// Look up and instantiate the value class
final String name = type.getRawType().getName();
final int lastDollar = name.lastIndexOf("$");
final String valueName;
if (lastDollar > -1) {
final int lastDot = name.lastIndexOf(".");
valueName = name.substring(0, lastDot + 1).concat(name.substring(lastDollar + 1)) + VALUE_SUFFIX;
} else {
valueName = name + VALUE_SUFFIX;
}
final Class<T> cls;
try {
cls = (Class<T>) Class.forName(valueName);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("No builder found for @AutoMatter type: " + name, e);
}
// Find those magic remapping-of-name-annotations (SerializedName)
final Map<String, List<String>> serializedNameMethods = getSerializedNameMethods(gson, type.getRawType(), cls);
// If the interface passed to us didn't have any SerializedName annotations, go the fast path
// and just pass it on the type adapter chain,
// it will most likely end up in the ReflectiveTypeAdapterFactory, good riddance!
// If it was annotated, we create a TypeAdapter that knows how to poke the json into
// Java world submission.
materialized = serializedNameMethods.isEmpty() ? gson.getAdapter(cls) : createForInterface(gson, cls, serializedNameMethods);
} else {
// Maybe a value class with SerializedName annotations?
final Map<String, List<String>> serializedNameMethodsbuilder = new HashMap<>();
// Since AutoMatter supports inheritance we need to walk through all of the interfaces with
// AutoMatter annotations.
final Class<? super T> valueClass = type.getRawType();
for (Class<?> itf : valueClass.getInterfaces()) {
if (itf.getAnnotation(AutoMatter.class) != null) {
serializedNameMethodsbuilder.putAll(getSerializedNameMethods(gson, itf, valueClass));
}
}
final Map<String, List<String>> serializedNameMethods = serializedNameMethodsbuilder;
// applicable. Bye, bye! This should be the fast path.
if (serializedNameMethods.isEmpty()) {
return null;
}
// We create a TypeAdapter that knows how to read between the lines (A.K.A is annotation
// aware)
// and can translate the restricted Java world names to beautiful free form json fields. Nom!
materialized = createForValue(gson, this, type, serializedNameMethods);
}
// Cache the materialized type before returning
final TypeAdapter<T> existing = (TypeAdapter<T>) adapters.putIfAbsent(type, materialized);
return (existing != null) ? existing : materialized;
}
Aggregations