package generator; import com.fasterxml.jackson.core.type.TypeReference; import com.squareup.javapoet.*; import io.vavr.*; import io.vavr.collection.Map; import io.vavr.collection.Multimap; import io.vavr.control.Either; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import javax.lang.model.element.Modifier; import java.io.File; import java.io.IOException; import java.util.stream.Collectors; import static generator.utils.Initializer.initMapper; import static generator.utils.Initializer.initValue; import static generator.utils.Initializer.publicVavrClass; import static generator.utils.Serializer.expectedJson; /** * @author <a href="mailto:[email protected]">Ruslan Sennov</a> */ public class ParameterizedPojo { public static void main(String[] args) throws IOException { java.util.Map<String, Object> cases = new java.util.HashMap<>(); cases.put("TupleOfString", Tuple.of("A", "B")); cases.put("TupleOfTuple", Tuple.of("A", Tuple.of("A", "B"))); generate(cases); } static void generate(java.util.Map<String, Object> cases) throws IOException { TypeSpec.Builder pojoTest = TypeSpec.classBuilder("ParameterizedPojoTest") .addJavadoc("generated\n") .addModifiers(Modifier.PUBLIC); initMapper(pojoTest, "MAPPER"); cases.forEach((k, v) -> addCase(pojoTest, k, v)); JavaFile javaFile = JavaFile.builder("io.vavr.jackson.generated", pojoTest.build()) .indent(" ") .skipJavaLangImports(true) .build(); javaFile.writeTo(new File("src/test/java")); } private static final java.util.Set<Class> generated = new java.util.HashSet<>(); private static void addCase(TypeSpec.Builder builder, String pojoName, Object value) { Class<?> clz = publicVavrClass(value.getClass()); if (!generated.contains(clz)) { int arity; if (clz == Tuple0.class) { arity = 0; } else if (clz == Tuple1.class) { arity = 1; } else if (clz == Tuple2.class) { arity = 2; } else if (clz == Tuple3.class) { arity = 3; } else if (clz == Tuple4.class) { arity = 4; } else if (clz == Tuple5.class) { arity = 5; } else if (clz == Tuple6.class) { arity = 6; } else if (clz == Tuple7.class) { arity = 7; } else if (clz == Tuple8.class) { arity = 8; } else if (Map.class.isAssignableFrom(clz) || Multimap.class.isAssignableFrom(clz) || Either.class.isAssignableFrom(clz)) { arity = 2; } else { arity = 1; } addPojo(builder, clz, arity); generated.add(clz); } addCase(builder, pojoName, value, clz.getSimpleName(), 0); } private static void addCase(TypeSpec.Builder builder, String pojoName, Object value, String clz, int opts) { MethodSpec.Builder testBuilder = MethodSpec.methodBuilder("test" + pojoName) .addAnnotation(Test.class) .addException(ClassName.get(Exception.class)); TypeName valueTypeName = initValue(testBuilder, "src", value); String genericts = ((ParameterizedTypeName) valueTypeName).typeArguments.stream().map(TypeName::toString).collect(Collectors.joining(", ")); MethodSpec testSpec = testBuilder .addStatement("$T json = MAPPER.writeValueAsString(new Parameterized$LPojo<>(src))", ClassName.get(String.class), clz) .addStatement("$T.assertEquals(json, $S)", ClassName.get(Assertions.class), "{\"value\":" + expectedJson(value, opts) + "}") .addStatement("Parameterized$LPojo<$L> restored =\n" + "MAPPER.readValue(json, new $T<Parameterized$LPojo<$L>>(){})", clz, genericts, ClassName.get(TypeReference.class), clz, genericts) .addStatement("$T.assertEquals(src, restored.getValue())", ClassName.get(Assertions.class)) .build(); builder.addMethod(testSpec); } private static void addPojo(TypeSpec.Builder builder, Class<?> clz, int arity) { String pojoName = "Parameterized" + clz.getSimpleName() + "Pojo"; TypeSpec.Builder pojoSpec = TypeSpec.classBuilder(pojoName) .addModifiers(Modifier.PUBLIC, Modifier.STATIC); TypeName[] types = new TypeName[arity]; for (int i = 1; i <= arity; i++) { types[i-1] = TypeVariableName.get("T" + i); pojoSpec.addTypeVariable(TypeVariableName.get("T" + i)); } TypeName type = ParameterizedTypeName.get(ClassName.get(clz), types); pojoSpec .addField(FieldSpec.builder(type, "v", Modifier.PRIVATE).build()) .addMethod(MethodSpec.constructorBuilder() .addModifiers(Modifier.PUBLIC) .build()) .addMethod(MethodSpec.constructorBuilder() .addModifiers(Modifier.PUBLIC) .addParameter(ParameterSpec.builder(type, "v").build()) .addStatement("this.v = v") .build()) .addMethod(MethodSpec.methodBuilder("getValue") .addModifiers(Modifier.PUBLIC) .returns(type) .addStatement("return v") .build()) .addMethod(MethodSpec.methodBuilder("setValue") .addModifiers(Modifier.PUBLIC) .returns(ClassName.get("", pojoName)) .addParameter(ParameterSpec.builder(type, "v").build()) .addStatement("this.v = v") .addStatement("return this") .build()) .build(); builder.addType(pojoSpec.build()); } }