-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
30 changed files
with
1,017 additions
and
239 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<groupId>com.infobip</groupId> | ||
<artifactId>infobip-spring-data-querydsl</artifactId> | ||
<version>3.0.1-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>infobip-spring-data-common</artifactId> | ||
|
||
<properties> | ||
<!-- DEPENDENCY VERSIONS --> | ||
<mssqlserver.version>1.12.3</mssqlserver.version> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.testcontainers</groupId> | ||
<artifactId>mssqlserver</artifactId> | ||
<version>${mssqlserver.version}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-jdbc</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-test</artifactId> | ||
<exclusions> | ||
<exclusion> | ||
<groupId>junit</groupId> | ||
<artifactId>junit</artifactId> | ||
</exclusion> | ||
</exclusions> | ||
</dependency> | ||
</dependencies> | ||
</project> |
2 changes: 1 addition & 1 deletion
2
...obip/spring/data/jpa/DatabaseCreator.java → ...p/spring/data/common/DatabaseCreator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
.../LicenseAcceptedMSSQLServerContainer.java → .../LicenseAcceptedMSSQLServerContainer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<groupId>com.infobip</groupId> | ||
<artifactId>infobip-spring-data-querydsl</artifactId> | ||
<version>3.0.1-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>infobip-spring-data-jdbc-annotation-processor</artifactId> | ||
|
||
<properties> | ||
<!-- DEPENDENCY VERSIONS --> | ||
<auto-service.version>1.0-rc6</auto-service.version> | ||
<querydsl.version>4.2.3-SNAPSHOT</querydsl.version> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>com.google.auto.service</groupId> | ||
<artifactId>auto-service</artifactId> | ||
<version>${auto-service.version}</version> | ||
<scope>provided</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.querydsl</groupId> | ||
<artifactId>querydsl-apt</artifactId> | ||
<version>${querydsl.version}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.querydsl</groupId> | ||
<artifactId>querydsl-sql-codegen</artifactId> | ||
<version>${querydsl.version}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-data-jdbc</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.projectlombok</groupId> | ||
<artifactId>lombok</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
</project> |
128 changes: 128 additions & 0 deletions
128
...src/main/java/com/infobip/spring/data/jdbc/annotation/processor/CustomElementHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
package com.infobip.spring.data.jdbc.annotation.processor; | ||
|
||
import com.google.common.base.CaseFormat; | ||
import com.querydsl.apt.*; | ||
import com.querydsl.codegen.*; | ||
import com.querydsl.sql.ColumnMetadata; | ||
import org.springframework.data.relational.core.mapping.Column; | ||
import org.springframework.data.relational.core.mapping.Table; | ||
|
||
import javax.annotation.processing.RoundEnvironment; | ||
import javax.lang.model.element.*; | ||
import javax.lang.model.util.Elements; | ||
import java.util.*; | ||
import java.util.stream.Collectors; | ||
|
||
class CustomElementHandler extends TypeElementHandler { | ||
|
||
private final Elements elements; | ||
private final String defaultSchema; | ||
|
||
public CustomElementHandler(Configuration configuration, | ||
ExtendedTypeFactory typeFactory, | ||
TypeMappings typeMappings, | ||
QueryTypeFactory queryTypeFactory, | ||
Elements elements, | ||
RoundEnvironment roundEnv) { | ||
super(configuration, typeFactory, typeMappings, queryTypeFactory); | ||
this.elements = elements; | ||
this.defaultSchema = getDefaultSchema(roundEnv); | ||
} | ||
|
||
private String getDefaultSchema(RoundEnvironment roundEnv) { | ||
Set<? extends Element> defaultSchemaElements = roundEnv.getElementsAnnotatedWith(DefaultSchema.class); | ||
|
||
if(defaultSchemaElements.isEmpty()) { | ||
return null; | ||
} | ||
|
||
if(defaultSchemaElements.size() > 1) { | ||
throw new IllegalArgumentException("found multiple elements with DefaultSchema " + defaultSchemaElements); | ||
} | ||
|
||
return defaultSchemaElements.iterator().next().getAnnotation(DefaultSchema.class).value(); | ||
} | ||
|
||
@Override | ||
public EntityType handleEntityType(TypeElement element) { | ||
EntityType entityType = super.handleEntityType(element); | ||
updateModel(element, entityType); | ||
return entityType; | ||
} | ||
|
||
private void updateModel(TypeElement element, EntityType type) { | ||
Map<Object, Object> data = type.getData(); | ||
data.put("table", getTableName(type)); | ||
getSchema(element, data).ifPresent(schema -> data.put("schema", schema)); | ||
|
||
Map<String, Integer> fieldNameToIndex = getFieldNameToIndex(type); | ||
|
||
type.getProperties() | ||
.forEach(property -> { | ||
property.getData().put("COLUMN", ColumnMetadata.named(getColumnName(property)) | ||
.withIndex(fieldNameToIndex.get(property.getName()))); | ||
}); | ||
} | ||
|
||
private Optional<String> getSchema(TypeElement element, Map<Object, Object> data) { | ||
Schema elementSchema = element.getAnnotation(Schema.class); | ||
|
||
if(Objects.isNull(elementSchema)) { | ||
return Optional.ofNullable(defaultSchema); | ||
} | ||
|
||
return Optional.of(elementSchema.value()); | ||
} | ||
|
||
private String getTableName(EntityType model) { | ||
String simpleName = simpleNameWithoutPrefix(model.getSimpleName()); | ||
String className = model.getPackageName() + "." + simpleName; | ||
return Optional.ofNullable(elements.getTypeElement(className) | ||
.getAnnotation(Table.class)) | ||
.map(Table::value) | ||
.orElse(simpleName); | ||
} | ||
|
||
private String getColumnName(Property property) { | ||
String name = nameWithoutPrefix(property.getDeclaringType().getPackageName(), | ||
property.getDeclaringType().getSimpleName()); | ||
TypeElement parentType = elements.getTypeElement(name); | ||
return parentType.getEnclosedElements() | ||
.stream() | ||
.filter(element -> element instanceof VariableElement) | ||
.map(element -> (VariableElement) element) | ||
.filter(element -> element.getSimpleName().toString().equals(property.getName())) | ||
.filter(element -> element.getAnnotation(Column.class) != null) | ||
.map(element -> element.getAnnotation(Column.class).value()) | ||
.findAny() | ||
.orElseGet(() -> CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, property.getName())); | ||
} | ||
|
||
private Map<String, Integer> getFieldNameToIndex(EntityType model) { | ||
String name = nameWithoutPrefix(model.getPackageName(), model.getSimpleName()); | ||
TypeElement typeElement = elements.getTypeElement(name); | ||
List<? extends Element> fields = typeElement.getEnclosedElements() | ||
.stream() | ||
.filter(element -> element.getKind().equals(ElementKind.FIELD)) | ||
.collect(Collectors.toList()); | ||
|
||
Map<String, Integer> fieldNameToIndex = new HashMap<>(); | ||
|
||
for (int index = 0; index < fields.size(); index++) { | ||
fieldNameToIndex.put(fields.get(index).getSimpleName().toString(), index + 1); | ||
} | ||
return fieldNameToIndex; | ||
} | ||
|
||
private String simpleNameWithoutPrefix(String simpleName) { | ||
return simpleName.substring(1); | ||
} | ||
|
||
private String nameWithoutPrefix(String packageName, String simpleName) { | ||
return name(packageName, simpleNameWithoutPrefix(simpleName)); | ||
} | ||
|
||
private String name(String packageName, String simpleName) { | ||
return packageName + "." + simpleName; | ||
} | ||
} |
59 changes: 59 additions & 0 deletions
59
...ain/java/com/infobip/spring/data/jdbc/annotation/processor/CustomExtendedTypeFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package com.infobip.spring.data.jdbc.annotation.processor; | ||
|
||
import com.google.common.base.Function; | ||
import com.mysema.codegen.model.*; | ||
import com.querydsl.codegen.*; | ||
|
||
import javax.annotation.processing.ProcessingEnvironment; | ||
import javax.lang.model.element.Modifier; | ||
import javax.lang.model.element.TypeElement; | ||
import javax.lang.model.type.TypeMirror; | ||
import javax.lang.model.util.Elements; | ||
import java.lang.annotation.Annotation; | ||
import java.util.List; | ||
import java.util.Set; | ||
|
||
class CustomExtendedTypeFactory extends com.querydsl.apt.ExtendedTypeFactory { | ||
|
||
private final Elements elements; | ||
|
||
public CustomExtendedTypeFactory( | ||
ProcessingEnvironment env, | ||
Set<Class<? extends Annotation>> annotations, | ||
TypeMappings typeMappings, | ||
QueryTypeFactory queryTypeFactory, | ||
Function<EntityType, String> variableNameFunction) { | ||
super(env, annotations, typeMappings, queryTypeFactory, variableNameFunction); | ||
this.elements = env.getElementUtils(); | ||
} | ||
|
||
@Override | ||
protected Type createType(TypeElement typeElement, TypeCategory category, | ||
List<? extends TypeMirror> typeArgs, boolean deep) { | ||
String simpleName = getSimpleName(typeElement, category); | ||
String name = elements.getPackageOf(typeElement) + "." + simpleName; | ||
String packageName = elements.getPackageOf(typeElement).getQualifiedName().toString(); | ||
Type[] params = new Type[typeArgs.size()]; | ||
for (int i = 0; i < params.length; i++) { | ||
params[i] = getType(typeArgs.get(i), deep); | ||
} | ||
return new SimpleType(category, name, packageName, simpleName, false, | ||
typeElement.getModifiers().contains(Modifier.FINAL), params); | ||
} | ||
|
||
private String getSimpleName(TypeElement typeElement, TypeCategory category) { | ||
if (category.equals(TypeCategory.ENTITY)) { | ||
return "Q" + typeElement.getSimpleName().toString(); | ||
} | ||
|
||
return typeElement.getSimpleName().toString(); | ||
} | ||
|
||
@Override | ||
public boolean isSimpleTypeEntity(TypeElement typeElement, Class<? extends Annotation> entityAnn) { | ||
return typeElement.getAnnotation(entityAnn) != null | ||
|| typeElement.getEnclosedElements() | ||
.stream() | ||
.anyMatch(element -> element.getAnnotation(entityAnn) != null); | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
...cessor/src/main/java/com/infobip/spring/data/jdbc/annotation/processor/DefaultSchema.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.infobip.spring.data.jdbc.annotation.processor; | ||
|
||
import java.lang.annotation.*; | ||
|
||
@Retention(RetentionPolicy.SOURCE) | ||
@Target({ ElementType.TYPE }) | ||
@Documented | ||
public @interface DefaultSchema { | ||
|
||
String value(); | ||
} |
11 changes: 11 additions & 0 deletions
11
...ion-processor/src/main/java/com/infobip/spring/data/jdbc/annotation/processor/Schema.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.infobip.spring.data.jdbc.annotation.processor; | ||
|
||
import java.lang.annotation.*; | ||
|
||
@Retention(RetentionPolicy.SOURCE) | ||
@Target({ ElementType.TYPE }) | ||
@Documented | ||
public @interface Schema { | ||
|
||
String value(); | ||
} |
77 changes: 77 additions & 0 deletions
77
.../com/infobip/spring/data/jdbc/annotation/processor/SpringDataJdbcAnnotationProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package com.infobip.spring.data.jdbc.annotation.processor; | ||
|
||
import com.google.auto.service.AutoService; | ||
import com.querydsl.apt.*; | ||
import com.querydsl.codegen.*; | ||
import org.springframework.data.annotation.Id; | ||
|
||
import javax.annotation.processing.*; | ||
import javax.lang.model.element.Element; | ||
import javax.lang.model.element.TypeElement; | ||
import java.lang.annotation.*; | ||
import java.util.Set; | ||
import java.util.stream.Collectors; | ||
|
||
@SupportedAnnotationTypes("org.springframework.data.annotation.Id") | ||
@AutoService(Processor.class) | ||
public class SpringDataJdbcAnnotationProcessor extends AbstractQuerydslProcessor { | ||
|
||
private RoundEnvironment roundEnv; | ||
private CustomExtendedTypeFactory typeFactory; | ||
private Configuration conf; | ||
|
||
@Override | ||
protected Configuration createConfiguration(RoundEnvironment roundEnv) { | ||
Class<? extends Annotation> entity = Id.class; | ||
this.roundEnv = roundEnv; | ||
CodegenModule codegenModule = new CodegenModule(); | ||
JavaTypeMappings typeMappings = new JavaTypeMappings(); | ||
codegenModule.bind(TypeMappings.class, typeMappings); | ||
codegenModule.bind(QueryTypeFactory.class, new QueryTypeFactoryImpl("", "", "")); | ||
SpringDataJdbcConfiguration springDataJdbcConfiguration = new SpringDataJdbcConfiguration(roundEnv, | ||
processingEnv, | ||
entity, null, null, | ||
null, Ignored.class, | ||
typeMappings, | ||
codegenModule); | ||
this.conf = springDataJdbcConfiguration; | ||
return springDataJdbcConfiguration; | ||
} | ||
|
||
@Override | ||
protected TypeElementHandler createElementHandler(TypeMappings typeMappings, QueryTypeFactory queryTypeFactory) { | ||
return new CustomElementHandler(conf, typeFactory, typeMappings, queryTypeFactory, processingEnv.getElementUtils(), roundEnv); | ||
} | ||
|
||
@Override | ||
protected CustomExtendedTypeFactory createTypeFactory(Set<Class<? extends Annotation>> entityAnnotations, | ||
TypeMappings typeMappings, | ||
QueryTypeFactory queryTypeFactory) { | ||
CustomExtendedTypeFactory customExtendedTypeFactory = new CustomExtendedTypeFactory(processingEnv, | ||
entityAnnotations, | ||
typeMappings, | ||
queryTypeFactory, | ||
conf.getVariableNameFunction()); | ||
this.typeFactory = customExtendedTypeFactory; | ||
return customExtendedTypeFactory; | ||
} | ||
|
||
protected Set<TypeElement> collectElements() { | ||
return roundEnv.getElementsAnnotatedWith(conf.getEntityAnnotation()) | ||
.stream() | ||
.map(Element::getEnclosingElement) | ||
.filter(element -> element instanceof TypeElement) | ||
.map(element -> (TypeElement) element) | ||
.collect(Collectors.toSet()); | ||
} | ||
|
||
@Override | ||
protected String getClassName(EntityType model) { | ||
return model.getFullName(); | ||
} | ||
|
||
@Documented | ||
@Retention(RetentionPolicy.RUNTIME) | ||
private @interface Ignored { | ||
} | ||
} |
Oops, something went wrong.