fi.jubic.easymapper.generator.JooqMapperGenerator Maven / Gradle / Ivy
package fi.jubic.easymapper.generator;
import com.google.auto.service.AutoService;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeVariableName;
import com.squareup.javapoet.WildcardTypeName;
import fi.jubic.easymapper.MappingException;
import fi.jubic.easymapper.ReferenceCollector;
import fi.jubic.easymapper.generator.def.PropertyDef;
import fi.jubic.easymapper.generator.def.ValueDef;
import fi.jubic.easymapper.jooq.Jooq;
import fi.jubic.easymapper.jooq.JooqFieldAccessor;
import fi.jubic.easymapper.jooq.JooqReferenceAccessor;
import fi.jubic.easymapper.jooq.RecordMapper;
import org.jooq.Record;
import org.jooq.Table;
import org.jooq.TableField;
import javax.annotation.processing.Messager;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@AutoService(Processor.class)
@SupportedAnnotationTypes({"fi.jubic.easymapper.annotations.EasyId"})
public class JooqMapperGenerator extends AbstractMapperGenerator {
private static final TypeVariableName R = TypeVariableName.get("R");
private static final String FIELD_NAME_TABLE = "table";
private static final TypeName TYPE_TABLE = ParameterizedTypeName.get(
ClassName.get(Table.class),
R
);
@Override
public Optional generate(
ValueDef valueDef,
Messager messager,
RoundEnvironment roundEnvironment
) {
if (!valueDef.getId().isPresent()) {
return Optional.empty();
}
String selfName = valueDef.getName() + "RecordMapper";
TypeName superInterface = ParameterizedTypeName.get(
ClassName.get(RecordMapper.class),
R,
TypeName.get(valueDef.getElement().asType()),
TypeName.get(valueDef.getBuilder().asType())
);
TypeSpec.Builder mapperBuilder = TypeSpec.classBuilder(selfName)
.addModifiers(Modifier.PUBLIC)
.addTypeVariable(TypeVariableName.get("R", ClassName.get(Record.class)))
.addSuperinterface(superInterface)
.addField(
FieldSpec.builder(
TYPE_TABLE,
FIELD_NAME_TABLE,
Modifier.PRIVATE,
Modifier.FINAL
).build()
);
// Property accessors
valueDef.getProperties().forEach(
property -> mapperBuilder.addField(
FieldSpec.builder(
typeJooqFieldAccessor(property.getType()),
firstToLower(property.getName() + "Accessor"),
Modifier.PRIVATE,
Modifier.FINAL
).build()
)
);
// Reference accessors
valueDef.getReferences().forEach(
reference -> mapperBuilder.addField(
FieldSpec.builder(
typeJooqReferenceAccessor(
WildcardTypeName.subtypeOf(ClassName.get(Object.class)),
reference
),
firstToLower(reference.getName() + "Accessor"),
Modifier.PRIVATE,
Modifier.FINAL
).build()
)
);
// Reference mappers
valueDef.getReferences().forEach(
reference -> mapperBuilder.addField(
FieldSpec.builder(
typeRecordMapper(reference),
firstToLower(reference.getName()) + "Mapper",
Modifier.PRIVATE,
Modifier.FINAL
).build()
)
);
// region Constructor
{
MethodSpec.Builder constructorBuilder = MethodSpec
.constructorBuilder()
.addModifiers(Modifier.PRIVATE)
.addParameter(TYPE_TABLE, FIELD_NAME_TABLE)
.addStatement("this.table = table");
valueDef.getProperties().forEach(
property -> constructorBuilder
.addParameter(
typeJooqFieldAccessor(property.getType()),
firstToLower(property.getName()) + "Accessor"
)
.addStatement(
"this.$LAccessor = $LAccessor",
firstToLower(property.getName()),
firstToLower(property.getName())
)
);
valueDef.getReferences().forEach(
reference -> constructorBuilder
.addParameter(
typeJooqReferenceAccessor(
WildcardTypeName.subtypeOf(TypeName.get(Object.class)),
reference
),
firstToLower(reference.getName()) + "Accessor"
)
.addStatement(
"this.$LAccessor = $LAccessor",
firstToLower(reference.getName()),
firstToLower(reference.getName())
)
);
valueDef.getReferences().forEach(
reference -> constructorBuilder
.addParameter(
typeRecordMapper(reference),
firstToLower(reference.getName()) + "Mapper"
)
.addStatement(
"this.$LMapper = $LMapper",
firstToLower(reference.getName()),
firstToLower(reference.getName())
)
);
mapperBuilder.addMethod(constructorBuilder.build());
}
// endregion Constructor
// region Reference withers
valueDef.getReferences().forEach(reference -> {
String valueParams = Stream.of(
valueDef.getProperties().stream()
.map(prop -> "this."
+ firstToLower(
prop.getName() + "Accessor"
)
),
valueDef.getReferences().stream()
.map(ref -> "this."
+ firstToLower(
ref.getName() + "Accessor"
)
),
valueDef.getReferences().stream()
.map(ref -> {
if (ref.getName().equals(reference.getName())) {
return firstToLower(ref.getName() + "Mapper");
}
return "this." + firstToLower(ref.getName() + "Mapper");
})
)
.flatMap(Function.identity())
.collect(Collectors.joining(", "));
mapperBuilder.addMethod(
MethodSpec.methodBuilder("with" + firstToUpper(reference.getName()))
.addModifiers(Modifier.PUBLIC)
.returns(
ParameterizedTypeName.get(
ClassName.bestGuess(selfName),
R
)
)
.addParameter(
typeRecordMapper(reference),
firstToLower(reference.getName() + "Mapper")
)
.addStatement(
"return new $N<>(this.$L, $N)",
selfName,
FIELD_NAME_TABLE,
valueParams
)
.build()
);
}
);
// endregion Reference withers
// region Mangler::write
{
MethodSpec.Builder writeBuilder = MethodSpec.methodBuilder("write")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class)
.returns(R)
.addParameter(
ClassName.get(Record.class),
"output"
)
.addParameter(
TypeName.get(valueDef.getElement().asType()),
"value"
)
.addStatement("$T modifiedOutput = output.into(table)", R);
Stream
.concat(
valueDef.getProperties().stream()
.filter(property -> valueDef.getId()
.map(id -> !property.getName().equals(id.getName()))
.orElse(true)
),
valueDef.getReferences().stream()
)
.forEach(prop -> writeBuilder.addStatement(
"modifiedOutput = $N.write(modifiedOutput, value.$L$N())",
firstToLower(prop.getName() + "Accessor"),
prop.getAccess().getName(),
firstToUpper(prop.getName())
));
mapperBuilder.addMethod(
writeBuilder
.addStatement("return modifiedOutput")
.build()
);
}
// endregion Mangler::write
// region Mapper::intermediateMap
{
CodeBlock.Builder controlFlow = CodeBlock.builder()
.addStatement(
"$T.Builder builder = $T.builder()",
TypeName.get(valueDef.getElement().asType()),
TypeName.get(valueDef.getElement().asType())
);
valueDef.getProperties().forEach(
property -> controlFlow
.beginControlFlow(
"if ($LAccessor.shouldExtract())",
firstToLower(property.getName())
)
.addStatement(
"builder = builder.set$L($LAccessor.extract(inputRecord))",
firstToUpper(property.getName()),
firstToLower(property.getName())
)
.endControlFlow()
);
valueDef.getReferences().forEach(
reference -> controlFlow
.beginControlFlow(
"if ($LMapper != null)",
firstToLower(reference.getName())
)
.addStatement(
"builder = builder.set$L($LMapper.map(input))",
firstToUpper(reference.getName()),
firstToLower(reference.getName())
)
.endControlFlow()
);
controlFlow.addStatement("return builder");
mapperBuilder.addMethod(
MethodSpec.methodBuilder("intermediateMap")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class)
.returns(TypeName.get(valueDef.getBuilder().asType()))
.addParameter(
ClassName.get(Record.class),
"input"
)
.addStatement(
"$T inputRecord = input.into($N)",
R,
FIELD_NAME_TABLE
)
.beginControlFlow(
"if ($LAccessor.extract(inputRecord) == null)",
firstToLower(
valueDef.getId()
.orElseThrow(IllegalStateException::new)
.getName()
))
.addStatement("return null")
.endControlFlow()
.addCode(controlFlow.build())
.build()
);
}
// endregion Mapper::intermediateMap
// region Mapper::finalize
{
mapperBuilder.addMethod(
MethodSpec.methodBuilder("finalize")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class)
.returns(TypeName.get(valueDef.getElement().asType()))
.addParameter(
TypeName.get(valueDef.getBuilder().asType()),
"intermediate"
)
.addStatement("return intermediate.build()")
.build()
);
}
// endregion Mapper::finalize
{
TypeVariableName varI = TypeVariableName.get("I");
// region collectingWith reference
valueDef.getReferences().forEach(
reference -> mapperBuilder.addMethod(
MethodSpec
.methodBuilder(
"collectingWith"
+ firstToUpper(reference.getName())
)
.addModifiers(Modifier.PUBLIC)
.addTypeVariable(varI)
.returns(
ParameterizedTypeName.get(
ClassName.get(Collector.class),
ClassName.get(Record.class),
WildcardTypeName.subtypeOf(Object.class),
ParameterizedTypeName.get(
ClassName.get(Optional.class),
TypeName.get(
valueDef.getElement().asType()
)
)
)
)
.addParameter(
ParameterizedTypeName.get(
ClassName.get(Collector.class),
ClassName.get(Record.class),
WildcardTypeName.subtypeOf(Object.class),
ParameterizedTypeName.get(
ClassName.get(Optional.class),
reference.getType()
)
),
"collector"
)
.addStatement(
"return new $T<>("
+ "this, "
+ "collector, "
+ "($L, $L) -> $L.isPresent() "
+ "? $L.set$L($L.get()) "
+ ": $L)",
ReferenceCollector.class,
firstToLower(valueDef.getName()),
firstToLower(reference.getName()),
firstToLower(reference.getName()),
firstToLower(valueDef.getName()),
firstToUpper(reference.getName()),
firstToLower(reference.getName()),
firstToLower(valueDef.getName())
)
.build()
)
);
// endregion collectingWith reference
// region collectingWith collection
valueDef.getCollectionReferences().forEach(
reference -> mapperBuilder.addMethod(
MethodSpec
.methodBuilder(
"collectingWith"
+ firstToUpper(reference.getName())
)
.addModifiers(Modifier.PUBLIC)
.addTypeVariable(varI)
.returns(
ParameterizedTypeName.get(
ClassName.get(Collector.class),
ClassName.get(Record.class),
WildcardTypeName.subtypeOf(Object.class),
ParameterizedTypeName.get(
ClassName.get(Optional.class),
TypeName.get(
valueDef.getElement().asType()
)
)
)
)
.addParameter(
ParameterizedTypeName.get(
ClassName.get(Collector.class),
ClassName.get(Record.class),
WildcardTypeName.subtypeOf(Object.class),
reference.getType()
),
"collector"
)
.addStatement(
"return new $T<>("
+ "this, "
+ "collector, "
+ "($L, $L) -> "
+ "$L.set$L($L))",
ReferenceCollector.class,
firstToLower(valueDef.getName()),
firstToLower(reference.getName()),
firstToLower(valueDef.getName()),
firstToUpper(reference.getName()),
firstToLower(reference.getName())
)
.build()
)
);
// endregion collectingWith collection
// region collectingManyWith reference
valueDef.getReferences().forEach(
reference -> mapperBuilder.addMethod(
MethodSpec
.methodBuilder(
"collectingManyWith"
+ firstToUpper(reference.getName())
)
.addModifiers(Modifier.PUBLIC)
.addTypeVariable(varI)
.returns(
ParameterizedTypeName.get(
ClassName.get(Collector.class),
ClassName.get(Record.class),
WildcardTypeName.subtypeOf(Object.class),
ParameterizedTypeName.get(
ClassName.get(List.class),
TypeName.get(
valueDef.getElement().asType()
)
)
)
)
.addParameter(
ParameterizedTypeName.get(
ClassName.get(Collector.class),
ClassName.get(Record.class),
WildcardTypeName.subtypeOf(Object.class),
ParameterizedTypeName.get(
ClassName.get(Optional.class),
reference.getType()
)
),
"collector"
)
.addStatement(
"return partitionAndFlatten("
+ "$LAccessor, "
+ "table, "
+ "collectingWith$L(collector))",
valueDef.getId()
.map(id -> firstToLower(id.getName()))
.orElseThrow(() -> new IllegalStateException(
"Cannot collect without an ID"
)),
firstToUpper(reference.getName())
)
.build()
)
);
// endregion collectingManyWith reference
// region collectingManyWith collection
valueDef.getCollectionReferences().forEach(
reference -> mapperBuilder.addMethod(
MethodSpec
.methodBuilder(
"collectingManyWith"
+ firstToUpper(reference.getName())
)
.addModifiers(Modifier.PUBLIC)
.addTypeVariable(varI)
.returns(
ParameterizedTypeName.get(
ClassName.get(Collector.class),
ClassName.get(Record.class),
WildcardTypeName.subtypeOf(Object.class),
ParameterizedTypeName.get(
ClassName.get(List.class),
TypeName.get(
valueDef.getElement().asType()
)
)
)
)
.addParameter(
ParameterizedTypeName.get(
ClassName.get(Collector.class),
ClassName.get(Record.class),
WildcardTypeName.subtypeOf(Object.class),
reference.getType()
),
"collector"
)
.addStatement(
"return partitionAndFlatten("
+ "$LAccessor, "
+ "table, "
+ "collectingWith$L(collector))",
valueDef.getId()
.map(id -> firstToLower(id.getName()))
.orElseThrow(() -> new IllegalStateException(
"Cannot collect without an ID"
)),
firstToUpper(reference.getName())
)
.build()
)
);
// endregion collectingManyWith collection
}
// region alias
mapperBuilder.addMethod(
MethodSpec.methodBuilder("alias")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class)
.returns(
ParameterizedTypeName.get(
ClassName.bestGuess(selfName),
R
)
)
.addParameter(
ParameterizedTypeName.get(
ClassName.get(Table.class),
R
),
"alias"
)
.addStatement(
"return new $T<>(alias, $L)",
ClassName.bestGuess(selfName),
Stream.concat(
Stream
.concat(
valueDef.getProperties().stream(),
valueDef.getReferences().stream()
)
.map(PropertyDef::getName)
.map(this::firstToLower)
.map(name -> name + "Accessor.alias(alias)"),
valueDef.getReferences()
.stream()
.map(ref -> "null")
).collect(Collectors.joining(", "))
)
.build()
);
// endregion alias
// region table
mapperBuilder.addMethod(
MethodSpec.methodBuilder("table")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class)
.returns(
ParameterizedTypeName.get(
ClassName.get(Table.class),
R
)
)
.addStatement("return table")
.build()
);
// endregion table
// region builder()
mapperBuilder.addMethod(
MethodSpec.methodBuilder("builder")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addTypeVariable(
TypeVariableName.get(
"R",
ClassName.get(Record.class)
)
)
.returns(
ParameterizedTypeName.get(
ClassName.bestGuess("Builder"),
R
)
)
.addParameter(
ParameterizedTypeName.get(
ClassName.get(Table.class),
R
),
"table"
)
.addStatement(
"return new $T<>(table)",
ClassName.bestGuess("Builder")
)
.build()
);
// endregion builder()
// region Builder
{
TypeSpec.Builder builderBuilder = TypeSpec.classBuilder("Builder")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addTypeVariable(TypeVariableName.get("R", ClassName.get(Record.class)))
.addField(
ParameterizedTypeName.get(
ClassName.get(Table.class),
R
),
"table",
Modifier.PRIVATE,
Modifier.FINAL
);
// region fields
// Property accessors
valueDef.getProperties().forEach(
property -> builderBuilder.addField(
FieldSpec.builder(
typeJooqFieldAccessor(property.getType()),
firstToLower(property.getName() + "Accessor"),
Modifier.PRIVATE,
Modifier.FINAL
).build()
)
);
// Reference accessors
valueDef.getReferences().forEach(
reference -> builderBuilder.addField(
FieldSpec.builder(
typeJooqReferenceAccessor(
WildcardTypeName.subtypeOf(ClassName.get(Object.class)),
reference
),
firstToLower(reference.getName() + "Accessor"),
Modifier.PRIVATE,
Modifier.FINAL
).build()
)
);
// endregion fields
// region constructors
{
MethodSpec.Builder constructorBuilder = MethodSpec
.constructorBuilder()
.addModifiers(Modifier.PRIVATE)
.addParameter(TYPE_TABLE, FIELD_NAME_TABLE)
.addStatement("this.table = table");
valueDef.getProperties().forEach(
property -> constructorBuilder
.addParameter(
typeJooqFieldAccessor(property.getType()),
firstToLower(property.getName()) + "Accessor"
)
.addStatement(
"this.$LAccessor = $LAccessor",
firstToLower(property.getName()),
firstToLower(property.getName())
)
);
valueDef.getReferences().forEach(
reference -> constructorBuilder
.addParameter(
typeJooqReferenceAccessor(
WildcardTypeName.subtypeOf(
TypeName.get(Object.class)
),
reference
),
firstToLower(reference.getName()) + "Accessor"
)
.addStatement(
"this.$LAccessor = $LAccessor",
firstToLower(reference.getName()),
firstToLower(reference.getName())
)
);
builderBuilder.addMethod(constructorBuilder.build());
}
{
MethodSpec.Builder constructorBuilder = MethodSpec
.constructorBuilder()
.addModifiers(Modifier.PUBLIC)
.addParameter(TYPE_TABLE, FIELD_NAME_TABLE)
.addStatement("this.table = table");
valueDef.getProperties().forEach(
property -> constructorBuilder
.addStatement(
"this.$LAccessor = null",
firstToLower(property.getName())
)
);
valueDef.getReferences().forEach(
reference -> constructorBuilder
.addStatement(
"this.$LAccessor = null",
firstToLower(reference.getName())
)
);
builderBuilder.addMethod(constructorBuilder.build());
}
// endregion constructors
// region setters
valueDef.getProperties().forEach(property -> {
String name = String.format(
"set%sAccessor",
firstToUpper(property.getName())
);
TypeName returnType = ParameterizedTypeName.get(
ClassName.bestGuess("Builder"),
R
);
String builderParams = Stream.of(
Stream.of("this.table"),
valueDef.getProperties()
.stream()
.map(prop -> {
if (prop.getName().equals(property.getName())) {
return firstToLower(prop.getName()) + "Accessor";
}
return "this." + firstToLower(prop.getName()) + "Accessor";
}),
valueDef.getReferences()
.stream()
.map(ref -> "this." + firstToLower(ref.getName()) + "Accessor")
)
.flatMap(Function.identity())
.collect(Collectors.joining(", "));
builderBuilder.addMethod(
MethodSpec.methodBuilder(name)
.addModifiers(Modifier.PUBLIC)
.addParameter(
typeJooqFieldAccessor(property.getType()),
firstToLower(property.getName()) + "Accessor"
)
.returns(returnType)
.addStatement(
"return new Builder<>($L)",
builderParams
)
.build()
);
builderBuilder.addMethod(
MethodSpec
.methodBuilder(
String.format(
"without%s",
firstToUpper(property.getName())
)
)
.addModifiers(Modifier.PUBLIC)
.returns(returnType)
.addStatement(
"return $L(new $T<>())",
name,
ClassName.get(JooqFieldAccessor.NoOpAccessor.class)
)
.build()
);
builderBuilder.addMethod(
MethodSpec.methodBuilder(name)
.addModifiers(Modifier.PUBLIC)
.addParameter(
ParameterizedTypeName.get(
ClassName.get(TableField.class),
R,
property.getType()
),
"field"
)
.returns(returnType)
.addStatement(
"return $L($T.jooqField(field))",
name,
Jooq.class
)
.build()
);
TypeVariableName varF = TypeVariableName.get("F");
builderBuilder.addMethod(
MethodSpec.methodBuilder(name)
.addModifiers(Modifier.PUBLIC)
.addTypeVariable(varF)
.addParameter(
ParameterizedTypeName.get(
ClassName.get(TableField.class),
R,
varF
),
"field"
)
.addParameter(
ParameterizedTypeName.get(
ClassName.get(Function.class),
property.getType(),
varF
),
"write"
)
.addParameter(
ParameterizedTypeName.get(
ClassName.get(Function.class),
varF,
property.getType()
),
"extract"
)
.returns(returnType)
.addStatement(
"return $L($T.jooqField(field, write, extract))",
name,
Jooq.class
)
.build()
);
});
valueDef.getReferences().forEach(reference -> {
String name = String.format(
"set%sAccessor",
firstToUpper(reference.getName())
);
TypeName returnType = ParameterizedTypeName.get(
ClassName.bestGuess("Builder"),
R
);
String builderParams = Stream.of(
Stream.of("this.table"),
valueDef.getProperties()
.stream()
.map(prop -> "this." + firstToLower(prop.getName()) + "Accessor"),
valueDef.getReferences()
.stream()
.map(ref -> {
if (ref.getName().equals(reference.getName())) {
return firstToLower(ref.getName()) + "Accessor";
}
return "this." + firstToLower(ref.getName()) + "Accessor";
})
)
.flatMap(Function.identity())
.collect(Collectors.joining(", "));
builderBuilder.addMethod(
MethodSpec.methodBuilder(name)
.addModifiers(Modifier.PUBLIC)
.addParameter(
typeJooqReferenceAccessor(
WildcardTypeName.subtypeOf(
TypeName.get(Object.class)
),
reference
),
firstToLower(reference.getName()) + "Accessor"
)
.returns(returnType)
.addStatement(
"return new Builder<>($L)",
builderParams
)
.build()
);
builderBuilder.addMethod(
MethodSpec
.methodBuilder(
String.format(
"without%s",
firstToUpper(reference.getName())
)
)
.addModifiers(Modifier.PUBLIC)
.returns(returnType)
.addStatement(
"return $L($T.noOp())",
name,
ClassName.get(JooqReferenceAccessor.class)
)
.build()
);
TypeVariableName varIdentityT = TypeVariableName.get("ID");
builderBuilder.addMethod(
MethodSpec.methodBuilder(name)
.addModifiers(Modifier.PUBLIC)
.addTypeVariable(varIdentityT)
.addParameter(
ParameterizedTypeName.get(
ClassName.get(TableField.class),
R,
varIdentityT
),
"field"
)
.addParameter(
ParameterizedTypeName.get(
ClassName.get(Function.class),
reference.getType(),
varIdentityT
),
"idGetter"
)
.returns(returnType)
.addStatement(
"return $L($T.jooqReference(field, idGetter))",
name,
Jooq.class
)
.build()
);
});
// endregion setters
// region build
CodeBlock.Builder buildStatementBuilder = CodeBlock.builder()
.add("return new $T<>(this.table", ClassName.bestGuess(selfName));
Stream
.concat(
valueDef.getProperties().stream(),
valueDef.getReferences().stream()
)
.map(PropertyDef::getName)
.map(this::firstToLower)
.map(name -> ", $T.requireNonNull(this." + name + "Accessor)")
.forEach(code -> buildStatementBuilder.add(code, Objects.class));
valueDef.getReferences()
.forEach(ref -> buildStatementBuilder.add(", null"));
buildStatementBuilder.add(")");
builderBuilder.addMethod(
MethodSpec.methodBuilder("build")
.addModifiers(Modifier.PUBLIC)
.returns(
ParameterizedTypeName.get(
ClassName.bestGuess(selfName),
R
)
)
.addStatement(buildStatementBuilder.build())
.build()
);
// endregion build
mapperBuilder.addType(builderBuilder.build());
}
// endregion Builder
return Optional.of(mapperBuilder.build());
}
private TypeName typeJooqFieldAccessor(TypeName field) {
return ParameterizedTypeName.get(
ClassName.get(JooqFieldAccessor.class),
R,
field
);
}
private TypeName typeJooqReferenceAccessor(TypeName idField, PropertyDef property) {
return ParameterizedTypeName.get(
ClassName.get(JooqReferenceAccessor.class),
R,
idField,
property.getType(),
property.getReferenceElement()
.orElseThrow(() -> new MappingException("Invalid reference type"))
.getEnclosedElements()
.stream()
.filter(elem -> elem.getKind() == ElementKind.CLASS)
.filter(elem -> elem.getSimpleName().toString().equals("Builder"))
.findFirst()
.map(Element::asType)
.map(TypeName::get)
.orElseThrow(() -> new MappingException("Builder not found"))
);
}
private TypeName typeRecordMapper(PropertyDef property) {
return ParameterizedTypeName.get(
ClassName.get(RecordMapper.class),
WildcardTypeName.subtypeOf(Record.class),
property.getType(),
property.getReferenceElement()
.orElseThrow(() -> new MappingException("Invalid reference type"))
.getEnclosedElements()
.stream()
.filter(elem -> elem.getKind() == ElementKind.CLASS)
.filter(elem -> elem.getSimpleName().toString().equals("Builder"))
.findFirst()
.map(Element::asType)
.map(TypeName::get)
.orElseThrow(() -> new MappingException("Builder not found"))
);
}
private String firstToUpper(String input) {
return input.substring(0, 1).toUpperCase()
+ input.substring(1);
}
private String firstToLower(String input) {
return input.substring(0, 1).toLowerCase()
+ input.substring(1);
}
}