use of io.requery.Entity in project requery by requery.
the class EntityProcessor method process.
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
// types to generate in this round
Map<TypeElement, EntityElement> entities = new HashMap<>();
SourceLanguage.map(processingEnv);
Types types = processingEnv.getTypeUtils();
Set<TypeElement> annotationElements = new LinkedHashSet<>();
if (isEmptyKotlinAnnotationSet(annotations)) {
annotationElements.addAll(SourceLanguage.getAnnotations());
} else {
annotationElements.addAll(annotations);
}
for (TypeElement annotation : annotationElements) {
for (Element element : roundEnv.getElementsAnnotatedWith(annotation)) {
typeElementOf(element).ifPresent(typeElement -> {
EntityElement entity = null;
if (isEntity(typeElement)) {
entity = computeType(entities, typeElement);
String model = entity.modelName();
graphs.computeIfAbsent(model, key -> new EntityGraph(types, embeddedTypes)).add(entity);
} else if (isSuperclass(typeElement)) {
entity = computeType(superTypes, typeElement);
} else if (isEmbeddable(typeElement)) {
entity = computeType(embeddedTypes, typeElement);
}
if (entity != null) {
entity.addAnnotationElement(annotation, element);
}
});
}
}
// process
boolean hasErrors = false;
Set<ElementValidator> validators = new LinkedHashSet<>();
Elements elements = processingEnv.getElementUtils();
for (EntityElement entity : entities.values()) {
// add the annotated elements from the super type (if any)
if (entity.element().getKind() == ElementKind.INTERFACE) {
List<? extends TypeMirror> interfaces = entity.element().getInterfaces();
for (TypeMirror mirror : interfaces) {
TypeElement superElement = elements.getTypeElement(mirror.toString());
if (superElement != null) {
mergeSuperType(entity, superElement);
}
}
}
TypeMirror typeMirror = entity.element().getSuperclass();
while (typeMirror.getKind() != TypeKind.NONE) {
TypeElement superElement = elements.getTypeElement(typeMirror.toString());
if (superElement != null) {
mergeSuperType(entity, superElement);
typeMirror = superElement.getSuperclass();
} else {
break;
}
}
// process the entity
Set<ElementValidator> results = entity.process(processingEnv);
validators.addAll(results);
}
for (EntityElement entity : embeddedTypes.values()) {
Set<ElementValidator> results = entity.process(processingEnv);
validators.addAll(results);
}
for (EntityGraph graph : graphs.values()) {
EntityGraphValidator validator = new EntityGraphValidator(processingEnv, graph);
Set<ElementValidator> results = validator.validate();
validators.addAll(results);
}
if (ElementValidator.hasErrors(validators)) {
hasErrors = true;
StringBuilder sb = new StringBuilder("Model has error(s) code generation may fail: ");
validators.forEach(validator -> sb.append(validator.toString()));
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, sb);
}
// generate
Set<SourceGenerator> generators = new LinkedHashSet<>();
if (!hasErrors || getOption(GENERATE_ALWAYS, true)) {
for (EntityDescriptor entity : entities.values()) {
EntityGraph graph = graphs.get(entity.modelName());
if (graph != null) {
generators.add(new EntityGenerator(processingEnv, graph, entity, null));
}
}
}
if (getOption(GENERATE_MODEL, true)) {
Map<String, Collection<EntityDescriptor>> packagesMap = new LinkedHashMap<>();
Set<EntityDescriptor> allEntities = graphs.values().stream().flatMap(graph -> graph.entities().stream()).collect(Collectors.toSet());
for (EntityDescriptor entity : allEntities) {
EntityGraph graph = graphs.get(entity.modelName());
String packageName = findModelPackageName(graph);
packagesMap.computeIfAbsent(packageName, key -> new LinkedHashSet<>());
packagesMap.get(packageName).addAll(graph.entities());
}
for (EntityDescriptor entity : entities.values()) {
EntityGraph graph = graphs.get(entity.modelName());
String packageName = findModelPackageName(graph);
if (entity.generatesAdditionalTypes()) {
packagesMap.remove(packageName);
}
}
generators.addAll(packagesMap.entrySet().stream().filter(entry -> !entry.getValue().isEmpty()).filter(entry -> !generatedModelPackages.contains(entry.getKey())).map(entry -> {
generatedModelPackages.add(entry.getKey());
return entry;
}).map(entry -> new ModelGenerator(processingEnv, entry.getKey(), entry.getValue())).collect(Collectors.toList()));
}
for (SourceGenerator generator : generators) {
try {
generator.generate();
} catch (IOException e) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage());
}
}
return false;
}
use of io.requery.Entity in project requery by requery.
the class EntityType method builderType.
@Override
public Optional<TypeMirror> builderType() {
Optional<Entity> entityAnnotation = annotationOf(Entity.class);
if (entityAnnotation.isPresent()) {
Entity entity = entityAnnotation.get();
Elements elements = processingEnvironment.getElementUtils();
TypeMirror mirror = null;
try {
// easiest way to get the class TypeMirror
Class<?> builderClass = entity.builder();
if (builderClass != void.class) {
mirror = elements.getTypeElement(builderClass.getName()).asType();
}
} catch (MirroredTypeException typeException) {
mirror = typeException.getTypeMirror();
}
if (mirror != null && mirror.getKind() != TypeKind.VOID) {
return Optional.of(mirror);
}
}
if (builderFactoryMethod().isPresent()) {
return Optional.of(builderFactoryMethod().get().getReturnType());
}
return ElementFilter.typesIn(element().getEnclosedElements()).stream().filter(element -> element.getSimpleName().toString().contains("Builder")).map(Element::asType).filter(Objects::nonNull).filter(type -> type.getKind() != TypeKind.VOID).findFirst();
}
use of io.requery.Entity in project requery by requery.
the class EntityType method process.
@Override
public Set<ElementValidator> process(ProcessingEnvironment processingEnvironment) {
// create attributes for fields that have no annotations
if (element().getKind().isInterface() || isImmutable() || isUnimplementable()) {
ElementFilter.methodsIn(element().getEnclosedElements()).stream().filter(this::isMethodProcessable).forEach(this::computeAttribute);
} else {
// private/static/final members fields are skipped
Set<VariableElement> elements = ElementFilter.fieldsIn(element().getEnclosedElements()).stream().filter(element -> !element.getModifiers().contains(Modifier.PRIVATE) && !element.getModifiers().contains(Modifier.STATIC) && (!element.getModifiers().contains(Modifier.FINAL) || isImmutable())).collect(Collectors.toSet());
if (elements.isEmpty()) {
// if nothing to process try the getters instead
ElementFilter.methodsIn(element().getEnclosedElements()).stream().filter(this::isMethodProcessable).forEach(this::computeAttribute);
} else {
elements.forEach(this::computeAttribute);
}
}
// find listener annotated methods
ElementFilter.methodsIn(element().getEnclosedElements()).forEach(element -> ListenerAnnotations.all().forEach(annotation -> {
if (element.getAnnotation(annotation) != null) {
ListenerMethod listener = listeners.computeIfAbsent(element, key -> new ListenerMethod(element));
listener.annotations().put(annotation, element.getAnnotation(annotation));
}
}));
Set<ProcessableElement<?>> elements = new LinkedHashSet<>();
attributes().values().forEach(attribute -> elements.add((ProcessableElement<?>) attribute));
elements.addAll(listeners.values());
Set<ElementValidator> validations = new LinkedHashSet<>();
elements.forEach(element -> validations.addAll(element.process(processingEnvironment)));
ElementValidator validator = new ElementValidator(element(), processingEnvironment);
Entity entity = annotationOf(Entity.class).orElse(null);
if (entity != null && !Names.isEmpty(entity.name()) && !SourceVersion.isIdentifier(entity.name())) {
validator.error("Invalid class identifier " + entity.name(), Entity.class);
}
if (element().getNestingKind() == NestingKind.ANONYMOUS) {
validator.error("Entity annotation cannot be applied to anonymous class");
}
if (element().getKind() == ElementKind.ENUM) {
validator.error("Entity annotation cannot be applied to an enum class");
}
if (attributes.values().isEmpty()) {
validator.warning("Entity contains no attributes");
}
if (!isReadOnly() && !isEmbedded() && attributes.values().size() == 1 && attributes.values().iterator().next().isGenerated()) {
validator.warning("Entity contains only a single generated attribute may fail to persist");
}
checkReserved(tableName(), validator);
validations.add(validator);
return validations;
}
use of io.requery.Entity in project requery by requery.
the class EntityType method typeName.
@Override
public QualifiedName typeName() {
String entityName = Stream.of(Mirrors.findAnnotationMirror(element(), Entity.class), Mirrors.findAnnotationMirror(element(), javax.persistence.Entity.class)).filter(Optional::isPresent).map(Optional::get).map(mirror -> Mirrors.findAnnotationValue(mirror, "name")).filter(Optional::isPresent).map(Optional::get).map(value -> value.getValue().toString()).filter(name -> !Names.isEmpty(name)).findAny().orElse("");
Elements elements = processingEnvironment.getElementUtils();
String packageName = elements.getPackageOf(element()).getQualifiedName().toString();
// if set in the annotation just use that
if (!Names.isEmpty(entityName)) {
return new QualifiedName(packageName, entityName);
}
String typeName = element().getSimpleName().toString();
if (element().getKind().isInterface()) {
// maybe I<Something> style
if (typeName.startsWith("I") && Character.isUpperCase(typeName.charAt(1))) {
entityName = typeName.substring(1);
} else {
entityName = typeName + "Entity";
}
} else {
entityName = Names.removeClassPrefixes(typeName);
if (entityName.equals(typeName)) {
entityName = typeName + (isImmutable() || isUnimplementable() ? "Type" : "Entity");
}
}
return new QualifiedName(packageName, entityName);
}
use of io.requery.Entity in project requery by requery.
the class JoinEntityGenerator method generate.
@Override
public void generate() throws IOException {
AssociativeEntityDescriptor descriptor = attribute.associativeEntity().orElseThrow(IllegalStateException::new);
String name = descriptor.name();
if (Names.isEmpty(name)) {
// create junction table name with TableA_TableB
name = from.tableName() + "_" + to.tableName();
}
ClassName entityName = nameResolver.joinEntityName(descriptor, from, to);
String className = "Abstract" + entityName.simpleName();
TypeSpec.Builder junctionType = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT).addSuperinterface(Serializable.class).addAnnotation(AnnotationSpec.builder(Entity.class).addMember("model", "$S", from.modelName()).addMember("stateless", "$L", from.isStateless()).build()).addAnnotation(AnnotationSpec.builder(Table.class).addMember("name", "$S", name).build());
CodeGeneration.addGeneratedAnnotation(processingEnvironment, junctionType);
Set<AssociativeReference> references = descriptor.columns();
EntityDescriptor[] entities = new EntityDescriptor[] { from, to };
Map<AssociativeReference, EntityDescriptor> map = new LinkedHashMap<>();
if (references.isEmpty()) {
// generate with defaults
for (int i = 0; i < entities.length; i++) {
EntityDescriptor type = entities[i];
String column = type.tableName() + "Id";
if (from == to) {
// if self referencing add a number to the column name
column += (i + 1);
}
AssociativeReference reference = new AssociativeReference(column, type.element(), null, ReferentialAction.CASCADE, ReferentialAction.CASCADE);
references.add(reference);
map.put(reference, type);
}
} else {
for (AssociativeReference reference : references) {
for (EntityDescriptor entity : entities) {
if (reference.referencedType() != null && reference.referencedType().equals(entity.element())) {
map.put(reference, entity);
}
}
}
}
int index = 0;
for (AssociativeReference reference : references) {
ClassName action = ClassName.get(ReferentialAction.class);
AnnotationSpec.Builder key = AnnotationSpec.builder(ForeignKey.class).addMember("delete", "$T.$L", action, reference.deleteAction().toString()).addMember("update", "$T.$L", action, reference.updateAction().toString());
TypeElement referenceElement = reference.referencedType();
EntityDescriptor entity = map.get(reference);
if (referenceElement == null) {
if (entity != null) {
referenceElement = entity.element();
} else {
referenceElement = entities[index++].element();
}
}
if (referenceElement != null) {
key.addMember("references", "$L.class", nameResolver.generatedTypeNameOf(referenceElement).orElseThrow(IllegalStateException::new));
}
if (reference.referencedColumn() != null) {
key.addMember("referencedColumn", "$S", reference.referencedColumn());
}
AnnotationSpec.Builder id = AnnotationSpec.builder(Key.class);
TypeName typeName = TypeName.get(Integer.class);
if (entity != null) {
Optional<? extends AttributeDescriptor> keyAttribute = entity.attributes().values().stream().filter(AttributeDescriptor::isKey).findAny();
if (keyAttribute.isPresent()) {
TypeMirror keyType = keyAttribute.get().typeMirror();
if (keyType.getKind().isPrimitive()) {
Types types = processingEnvironment.getTypeUtils();
keyType = types.boxedClass((PrimitiveType) keyType).asType();
}
typeName = TypeName.get(keyType);
}
}
FieldSpec.Builder field = FieldSpec.builder(typeName, reference.name(), Modifier.PROTECTED).addAnnotation(key.build()).addAnnotation(id.build());
junctionType.addField(field.build());
}
String packageName = entityName.packageName();
CodeGeneration.writeType(processingEnvironment, packageName, junctionType.build());
}
Aggregations