Skip to content

Commit cba91e8

Browse files
committed
1 parent d81eb07 commit cba91e8

File tree

2 files changed

+178
-0
lines changed

2 files changed

+178
-0
lines changed
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
package org.raml.ramltopojo.extensions.jackson1;
2+
3+
import com.google.common.base.Function;
4+
import com.google.common.collect.Lists;
5+
import com.squareup.javapoet.*;
6+
import joptsimple.internal.Strings;
7+
import org.codehaus.jackson.JsonGenerator;
8+
import org.codehaus.jackson.JsonParser;
9+
import org.codehaus.jackson.JsonProcessingException;
10+
import org.codehaus.jackson.map.DeserializationContext;
11+
import org.codehaus.jackson.map.ObjectMapper;
12+
import org.codehaus.jackson.map.SerializerProvider;
13+
import org.codehaus.jackson.map.annotate.JsonDeserialize;
14+
import org.codehaus.jackson.map.annotate.JsonSerialize;
15+
import org.codehaus.jackson.map.deser.std.StdDeserializer;
16+
import org.codehaus.jackson.map.ser.std.SerializerBase;
17+
import org.raml.ramltopojo.EventType;
18+
import org.raml.ramltopojo.Names;
19+
import org.raml.ramltopojo.extensions.UnionPluginContext;
20+
import org.raml.ramltopojo.extensions.UnionTypeHandlerPlugin;
21+
import org.raml.v2.api.model.v10.datamodel.ObjectTypeDeclaration;
22+
import org.raml.v2.api.model.v10.datamodel.TypeDeclaration;
23+
import org.raml.v2.api.model.v10.datamodel.UnionTypeDeclaration;
24+
25+
import javax.annotation.Nullable;
26+
import javax.lang.model.element.Modifier;
27+
import java.io.IOException;
28+
import java.util.Arrays;
29+
import java.util.List;
30+
import java.util.Map;
31+
32+
/**
33+
* Created. There, you have it.
34+
*/
35+
public class JacksonUnionExtension extends UnionTypeHandlerPlugin.Helper {
36+
37+
@Override
38+
public ClassName className(UnionPluginContext unionPluginContext, UnionTypeDeclaration ramlType, ClassName currentSuggestion, EventType eventType) {
39+
return currentSuggestion;
40+
}
41+
42+
@Override
43+
public TypeSpec.Builder classCreated(UnionPluginContext unionPluginContext, UnionTypeDeclaration ramlType, TypeSpec.Builder incoming, EventType eventType) {
44+
45+
ClassName deserializer =
46+
ClassName.get("", unionPluginContext.creationResult().getJavaName(EventType.INTERFACE).simpleName(),
47+
Names.typeName(ramlType.name(), "deserializer"));
48+
49+
ClassName serializer =
50+
ClassName.get("", unionPluginContext.creationResult().getJavaName(EventType.INTERFACE).simpleName(),
51+
Names.typeName("serializer"));
52+
53+
createSerializer(serializer, ramlType, incoming, eventType);
54+
createDeserializer(unionPluginContext, deserializer, ramlType, incoming, eventType);
55+
56+
incoming.addAnnotation(AnnotationSpec.builder(JsonDeserialize.class)
57+
.addMember("using", "$T.class", deserializer).build());
58+
incoming.addAnnotation(AnnotationSpec.builder(JsonSerialize.class)
59+
.addMember("using", "$T.class", serializer).build());
60+
61+
return incoming;
62+
}
63+
64+
private void createSerializer(ClassName serializerName, UnionTypeDeclaration union, TypeSpec.Builder typeBuilder, EventType eventType) {
65+
66+
if ( eventType == EventType.IMPLEMENTATION) {
67+
return;
68+
}
69+
70+
ClassName typeBuilderName = ClassName.get("", typeBuilder.build().name);
71+
TypeSpec.Builder builder = TypeSpec.classBuilder(serializerName)
72+
.addModifiers(Modifier.STATIC, Modifier.PUBLIC)
73+
.superclass(ParameterizedTypeName.get(ClassName.get(SerializerBase.class), typeBuilderName))
74+
.addMethod(
75+
MethodSpec.constructorBuilder()
76+
.addModifiers(Modifier.PUBLIC)
77+
.addCode("super($T.class);", typeBuilderName).build()
78+
79+
).addModifiers(Modifier.PUBLIC);
80+
MethodSpec.Builder serialize = MethodSpec.methodBuilder("serialize")
81+
.addModifiers(Modifier.PUBLIC)
82+
.addParameter(ParameterSpec.builder(typeBuilderName, "object").build())
83+
.addParameter(ParameterSpec.builder(ClassName.get(JsonGenerator.class), "jsonGenerator").build())
84+
.addParameter(ParameterSpec.builder(ClassName.get(SerializerProvider.class), "jsonSerializerProvider").build())
85+
.addException(IOException.class)
86+
.addException(JsonProcessingException.class);
87+
88+
for (TypeDeclaration typeDeclaration : union.of()) {
89+
90+
String isMethod = Names.methodName("is", typeDeclaration.name());
91+
String getMethod = Names.methodName("get", typeDeclaration.name());
92+
serialize.beginControlFlow("if ( object." + isMethod + "())");
93+
serialize.addStatement("jsonGenerator.writeObject(object." + getMethod + "())");
94+
serialize.addStatement("return");
95+
serialize.endControlFlow();
96+
}
97+
98+
serialize.addStatement("throw new $T($S + object)", IOException.class, "Can't figure out type of object");
99+
100+
builder.addMethod(serialize.build());
101+
typeBuilder.addType(builder.build());
102+
}
103+
104+
private void createDeserializer(UnionPluginContext unionPluginContext, ClassName serializerName, UnionTypeDeclaration union, TypeSpec.Builder typeBuilder, EventType eventType) {
105+
106+
if ( eventType == EventType.IMPLEMENTATION) {
107+
return;
108+
}
109+
110+
ClassName typeBuilderName = ClassName.get("", typeBuilder.build().name);
111+
112+
TypeSpec.Builder builder = TypeSpec.classBuilder(serializerName)
113+
.addModifiers(Modifier.STATIC, Modifier.PUBLIC)
114+
.superclass(ParameterizedTypeName.get(ClassName.get(StdDeserializer.class), typeBuilderName))
115+
.addMethod(
116+
MethodSpec.constructorBuilder()
117+
.addModifiers(Modifier.PUBLIC)
118+
.addCode("super($T.class);", typeBuilderName).build()
119+
120+
).addModifiers(Modifier.PUBLIC);
121+
122+
MethodSpec.Builder deserialize = MethodSpec.methodBuilder("deserialize")
123+
.addModifiers(Modifier.PUBLIC)
124+
.addParameter(ParameterSpec.builder(ClassName.get(JsonParser.class), "jsonParser").build())
125+
.addParameter(ParameterSpec.builder(ClassName.get(DeserializationContext.class), "jsonContext").build())
126+
.addException(IOException.class)
127+
.addException(JsonProcessingException.class)
128+
.returns(typeBuilderName)
129+
.addStatement("$T mapper = new $T()", ObjectMapper.class, ObjectMapper.class)
130+
.addStatement("$T<String, Object> map = mapper.readValue(jsonParser, Map.class)", Map.class);
131+
132+
133+
for (TypeDeclaration typeDeclaration : union.of()) {
134+
135+
TypeName unionPossibility = unionPluginContext.unionClass(typeDeclaration).getJavaName(EventType.IMPLEMENTATION);
136+
137+
String name = Names.methodName("looksLike", typeDeclaration.name());
138+
deserialize.addStatement("if ( " + name + "(map) ) return new $T(mapper.convertValue(map, $T.class))",
139+
unionPluginContext.creationResult().getJavaName(EventType.IMPLEMENTATION), unionPossibility);
140+
141+
buildLooksLike(builder, typeDeclaration);
142+
}
143+
144+
145+
deserialize.addStatement("throw new $T($S + map)", IOException.class, "Can't figure out type of object");
146+
builder.addMethod(deserialize.build());
147+
148+
typeBuilder.addType(builder.build());
149+
}
150+
151+
private void buildLooksLike(TypeSpec.Builder builder, TypeDeclaration typeDeclaration) {
152+
153+
String name = Names.methodName("looksLike", typeDeclaration.name());
154+
MethodSpec.Builder spec =
155+
MethodSpec.methodBuilder(name).addParameter(ParameterizedTypeName.get(ClassName.get(Map.class),
156+
ClassName.get(String.class),
157+
ClassName.get(Object.class)), "map");
158+
if (typeDeclaration instanceof ObjectTypeDeclaration) {
159+
160+
ObjectTypeDeclaration otd = (ObjectTypeDeclaration) typeDeclaration;
161+
List<String> names = Lists.transform(otd.properties(), new Function<TypeDeclaration, String>() {
162+
163+
@Nullable
164+
@Override
165+
public String apply(@Nullable TypeDeclaration input) {
166+
return "\"" + input.name() + "\"";
167+
}
168+
});
169+
170+
spec.addStatement("return map.keySet().containsAll($T.asList($L))", Arrays.class, Strings.join(names, ","));
171+
}
172+
173+
spec.addModifiers(Modifier.PRIVATE).returns(TypeName.BOOLEAN);
174+
builder.addMethod(spec.build());
175+
}
176+
177+
}

raml-to-pojo/src/main/resources/META-INF/ramltopojo-plugin.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ core.jsr303=org.raml.ramltopojo.extensions.jsr303.Jsr303Extension
22
core.jackson1=\
33
org.raml.ramltopojo.extensions.jackson1.JacksonBasicExtension,\
44
org.raml.ramltopojo.extensions.jackson1.JacksonDiscriminatorInheritanceTypeExtension,\
5+
org.raml.ramltopojo.extensions.jackson1.JacksonUnionExtension,\
56
org.raml.ramltopojo.extensions.jackson1.JacksonScalarTypeSerialization,\
67
org.raml.ramltopojo.extensions.jackson1.JacksonEnumExtension
78
core.jackson2=\

0 commit comments

Comments
 (0)