Skip to content

Commit bd6b9c3

Browse files
committed
Merge branch 'SentryMan-dedupJsonType' into feature/nima
2 parents 00a02ff + a77a237 commit bd6b9c3

File tree

4 files changed

+185
-127
lines changed

4 files changed

+185
-127
lines changed

.gitignore

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,9 @@ build/
33
.idea/
44
*.iml
55
.gradle
6-
http-generator-nima/.settings/org.eclipse.m2e.core.prefs
7-
http-generator-nima/.settings/org.eclipse.jdt.core.prefs
8-
http-generator-nima/.settings/org.eclipse.jdt.apt.core.prefs
9-
http-generator-nima/.settings/org.eclipse.core.resources.prefs
10-
http-generator-nima/.project
11-
http-generator-nima/.classpath
126
*.prefs
13-
tests/test-nima/.classpath
14-
tests/test-nima/.factorypath
15-
tests/test-nima/.project
16-
*.class
7+
*.class*
8+
*.factorypath
9+
*.project
10+
*.processors
11+
*/bin/

http-generator-nima/src/main/java/io/avaje/http/generator/helidon/nima/ControllerMethodWriter.java

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
package io.avaje.http.generator.helidon.nima;
22

3-
import io.avaje.http.api.MediaType;
4-
import io.avaje.http.generator.core.*;
5-
3+
import java.util.AbstractMap.SimpleImmutableEntry;
64
import java.util.List;
5+
import java.util.Map;
76
import java.util.Optional;
87

8+
import io.avaje.http.api.MediaType;
9+
import io.avaje.http.generator.core.Append;
10+
import io.avaje.http.generator.core.MethodParam;
11+
import io.avaje.http.generator.core.MethodReader;
12+
import io.avaje.http.generator.core.ParamType;
13+
import io.avaje.http.generator.core.PathSegments;
14+
import io.avaje.http.generator.core.ProcessingContext;
15+
import io.avaje.http.generator.core.WebMethod;
16+
917
/**
1018
* Write code to register Web route for a given controller method.
1119
*/
@@ -16,13 +24,20 @@ class ControllerMethodWriter {
1624
private final WebMethod webMethod;
1725
private final ProcessingContext ctx;
1826
private final boolean useJsonB;
19-
20-
ControllerMethodWriter(MethodReader method, Append writer, ProcessingContext ctx, boolean useJsonB) {
27+
private final Map<String, SimpleImmutableEntry<String, String>> jsonTypes;
28+
29+
ControllerMethodWriter(
30+
MethodReader method,
31+
Append writer,
32+
ProcessingContext ctx,
33+
boolean useJsonB,
34+
Map<String, SimpleImmutableEntry<String, String>> jsonTypes) {
2135
this.method = method;
2236
this.writer = writer;
23-
this.webMethod = method.getWebMethod();
37+
webMethod = method.getWebMethod();
2438
this.ctx = ctx;
2539
this.useJsonB = useJsonB;
40+
this.jsonTypes=jsonTypes;
2641
}
2742

2843
void writeRule() {
@@ -36,11 +51,21 @@ void writeHandler(boolean requestScoped) {
3651
final var bodyType = method.getBodyType();
3752
if (bodyType != null) {
3853
if (useJsonB) {
54+
55+
final var fieldName =
56+
method.getParams().stream()
57+
.filter(MethodParam::isBody)
58+
.findFirst()
59+
.orElseThrow()
60+
.getUType()
61+
.full()
62+
.transform(jsonTypes::get)
63+
.getValue();
3964
writer
40-
.append(
41-
" var %s = %sBodyJsonType.fromJson(req.content().inputStream());",
42-
method.getBodyName(), method.simpleName())
43-
.eol();
65+
.append(
66+
" var %s = %sJsonType.fromJson(req.content().inputStream());",
67+
method.getBodyName(), fieldName)
68+
.eol();
4469

4570
} else {
4671
// use default helidon content negotiation
@@ -103,7 +128,10 @@ void writeHandler(boolean requestScoped) {
103128
if (!method.isVoid()) {
104129
writeContextReturn();
105130
if (producesJson()) {
106-
writer.append(" %sReturnedJsonType.toJson(result, res.outputStream());", method.simpleName()).eol();
131+
132+
final var fieldName =
133+
method.getReturnType().toString().transform(jsonTypes::get).getValue();
134+
writer.append(" %sJsonType.toJson(result, res.outputStream());", fieldName).eol();
107135
} else {
108136
writer.append(" res.send(result);").eol();
109137
}
Lines changed: 109 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,40 @@
11
package io.avaje.http.generator.helidon.nima;
22

33
import java.io.IOException;
4+
import java.util.AbstractMap.SimpleImmutableEntry;
5+
import java.util.HashMap;
46
import java.util.List;
7+
import java.util.Map;
58
import java.util.Optional;
69

710
import javax.lang.model.type.DeclaredType;
11+
import javax.lang.model.type.PrimitiveType;
812

913
import io.avaje.http.generator.core.BaseControllerWriter;
1014
import io.avaje.http.generator.core.Constants;
1115
import io.avaje.http.generator.core.ControllerReader;
1216
import io.avaje.http.generator.core.MethodParam;
1317
import io.avaje.http.generator.core.MethodReader;
1418
import io.avaje.http.generator.core.ProcessingContext;
19+
import io.avaje.http.generator.core.UType;
1520

1621
/** Write Helidon specific web route adapter (a Helidon Service). */
1722
class ControllerWriter extends BaseControllerWriter {
1823

1924
private static final String AT_GENERATED = "@Generated(\"avaje-helidon-nima-generator\")";
2025
private final boolean useJsonB;
26+
private final Map<String, SimpleImmutableEntry<String, String>> jsonTypes;
2127

22-
ControllerWriter(ControllerReader reader, ProcessingContext ctx, boolean jsonB) throws IOException {
28+
ControllerWriter(ControllerReader reader, ProcessingContext ctx, boolean jsonB)
29+
throws IOException {
2330
super(reader, ctx);
24-
this.useJsonB = jsonB;
31+
useJsonB = jsonB;
2532
if (useJsonB) {
2633
reader.addImportType("io.avaje.jsonb.Jsonb");
2734
reader.addImportType("io.avaje.jsonb.JsonType");
35+
jsonTypes = new HashMap<>();
36+
} else {
37+
jsonTypes = null;
2838
}
2939
reader.addImportType("io.helidon.common.http.HttpMediaType");
3040
reader.addImportType("io.helidon.common.parameters.Parameters");
@@ -46,7 +56,7 @@ void write() {
4656
private List<ControllerMethodWriter> getWriterMethods() {
4757
return reader.getMethods().stream()
4858
.filter(MethodReader::isWebMethod)
49-
.map(it -> new ControllerMethodWriter(it, writer, ctx, useJsonB))
59+
.map(it -> new ControllerMethodWriter(it, writer, ctx, useJsonB, jsonTypes))
5060
.toList();
5161
}
5262

@@ -88,17 +98,16 @@ private void writeClassStart() {
8898
writer.append(" private final Validator validator;").eol();
8999
}
90100

91-
List<MethodReader> jsonMethods;
92101
if (useJsonB) {
93-
jsonMethods =
102+
103+
final var jsonMethods =
94104
reader.getMethods().stream()
95105
.filter(MethodReader::isWebMethod)
96106
.filter(m -> !"byte[]".equals(m.getReturnType().toString()))
97-
.filter(m -> m.getProduces() == null || m.getProduces().toLowerCase().contains("json"))
107+
.filter(
108+
m -> m.getProduces() == null || m.getProduces().toLowerCase().contains("json"))
98109
.toList();
99110
writeJsonBTypeFields(jsonMethods);
100-
} else {
101-
jsonMethods = null;
102111
}
103112
writer.eol();
104113

@@ -115,126 +124,129 @@ private void writeClassStart() {
115124
writer.append(" this.validator = validator;").eol();
116125
}
117126
if (useJsonB) {
118-
writeJsonBTypeAssignments(jsonMethods);
127+
writeJsonBTypeAssignments();
119128
}
120129
writer.append(" }").eol().eol();
121130
}
122131

123132
public void writeJsonBTypeFields(List<MethodReader> jsonMethods) {
124133
for (final MethodReader methodReader : jsonMethods) {
125-
// body types
126-
if (methodReader.getBodyType() != null) {
127-
methodReader.getParams().stream()
128-
.filter(MethodParam::isBody)
129-
.forEach(
130-
param ->
131-
writer
132-
.append(
133-
" private final JsonType<%s> %sBodyJsonType;",
134-
param.getUType().full(), methodReader.simpleName())
135-
.eol());
136-
}
137-
138-
if (methodReader.isVoid()) {
139-
continue;
140-
}
141-
142-
// return types
143-
if (methodReader.getReturnType() instanceof final DeclaredType fullType) {
144-
final var typeArgs = fullType.getTypeArguments();
145-
final var typeArgSize = typeArgs.size();
146-
147-
writer.append(" private final JsonType<");
148-
switch (typeArgSize) {
149-
case 1 -> {
150-
if (fullType.toString().contains("java.util.Set"))
151-
writer.append("java.util.Set<%s>>", typeArgs.get(0));
152-
else writer.append("java.util.List<%s>>", typeArgs.get(0));
153-
}
154-
case 2 -> writer.append("java.util.Map<String, %s>>", typeArgs.get(1));
155-
default -> writer.append("%s>", fullType);
156-
}
157-
writer.append(" %sReturnedJsonType;", methodReader.simpleName()).eol();
158-
} else {
159-
throw new UnsupportedOperationException("Only Objects are supported with Jsonb Return Types");
160-
}
161-
}
162-
}
163134

164-
public void writeJsonBTypeAssignments(List<MethodReader> jsonMethods) {
165-
for (final MethodReader methodReader : jsonMethods) {
166-
// body types
167-
writeBodyJsonType(methodReader);
135+
writeFieldJsonBodyType(methodReader);
168136
if (methodReader.isVoid()) {
169137
continue;
170138
}
171-
writeReturnJsonType(methodReader);
139+
writeFieldJsonReturnType(methodReader);
172140
}
173141
}
174142

175-
private void writeBodyJsonType(MethodReader methodReader) {
143+
public void writeFieldJsonBodyType(MethodReader methodReader) {
144+
// body types
176145
if (methodReader.getBodyType() != null) {
177146
methodReader.getParams().stream()
178147
.filter(MethodParam::isBody)
179148
.forEach(
180-
p -> {
181-
final var type = p.getUType();
182-
final var jsonType =
183-
Optional.ofNullable(type.param1())
184-
.or(() -> Optional.ofNullable(type.param0()))
185-
.orElseGet(type::full);
186-
writer.append(
187-
" this.%sBodyJsonType = jsonB.type(%s.class)",
188-
methodReader.simpleName(), jsonType);
189-
190-
if (type.param0() != null) {
191-
writer.append(".");
192-
switch (type.mainType()) {
193-
case "java.util.List" -> writer.append("list");
194-
case "java.util.Map" -> writer.append("map");
195-
case "java.util.Set" -> writer.append("set");
196-
default -> throw new UnsupportedOperationException(
197-
"Only java.util Map, Set and List are supported JsonB Controller Body Return Types");
198-
}
199-
writer.append("()");
200-
}
201-
writer.append(";").eol();
149+
param -> {
150+
final var fullType = param.getUType().full();
151+
jsonTypes.computeIfAbsent(
152+
fullType,
153+
type -> {
154+
final var baseType = getBaseType(param.getUType());
155+
final var fieldName = createFieldName(baseType, type);
156+
writer
157+
.append("private final JsonType<%s> %sJsonType;", type, fieldName)
158+
.eol();
159+
return new SimpleImmutableEntry<>(baseType, fieldName);
160+
});
202161
});
203162
}
204163
}
205164

206-
void writeReturnJsonType(MethodReader methodReader) {
165+
public void writeFieldJsonReturnType(MethodReader methodReader) {
166+
167+
// return types
207168
if (methodReader.getReturnType() instanceof final DeclaredType fullType) {
208-
final var typeArgs = fullType.getTypeArguments();
209-
final var typeArgSize = typeArgs.size();
210-
final var jsonType =
211-
switch (typeArgSize) {
212-
case 1 -> typeArgs.get(0);
213-
case 2 -> typeArgs.get(1);
214-
default -> fullType;
215-
};
216-
217-
writer.append(
218-
" this.%sReturnedJsonType = jsonB.type(%s.class)",
219-
methodReader.simpleName(), jsonType);
220-
final var returnType = fullType.toString();
221-
if (typeArgSize != 0) {
222-
writer.append(".");
169+
final var fullTypeString = fullType.toString();
170+
jsonTypes.computeIfAbsent(
171+
fullTypeString,
172+
type -> {
173+
final var baseType = getBaseType(fullType);
174+
final var fieldName = createFieldName(baseType, type);
175+
writer.append("private final JsonType<%s> %sJsonType;", type, fieldName).eol();
176+
return new SimpleImmutableEntry<>(baseType, fieldName);
177+
});
178+
} else if (methodReader.getReturnType() instanceof final PrimitiveType fullType) {
179+
180+
jsonTypes.computeIfAbsent(
181+
fullType.toString(),
182+
type -> {
183+
final var baseType =
184+
"int".equals(type)
185+
? "Integer"
186+
: type.substring(0, 1).toUpperCase() + type.substring(1);
187+
writer.append("private final JsonType<%s> %sJsonType;", baseType, type).eol();
188+
return new SimpleImmutableEntry<>(baseType, type);
189+
});
190+
} else {
191+
throw new UnsupportedOperationException(
192+
"Only Primitives and Objects are supported with Jsonb Return Types");
193+
}
194+
}
195+
196+
public void writeJsonBTypeAssignments() {
197+
for (final var entry : jsonTypes.entrySet()) {
198+
final var fullType = entry.getKey();
199+
final var element = entry.getValue();
200+
final var baseType = element.getKey();
201+
final var fieldName = element.getValue();
202+
203+
writer.append(" this.%sJsonType = jsonB.type(%s.class)", fieldName, baseType);
223204

224-
switch (returnType.substring(0, 13)) {
205+
if (fullType.contains("<")) {
206+
writer.append(".");
207+
switch (fullType.substring(0, 13)) {
225208
case "java.util.Lis" -> writer.append("list");
226209
case "java.util.Map" -> writer.append("map");
227210
case "java.util.Set" -> writer.append("set");
228211
default -> throw new UnsupportedOperationException(
229-
"Only java.util Map, Set and List are supported JsonB Controller Collection Return Types");
212+
"Only java.util Map, Set and List are supported JsonB Controller Collection Types");
230213
}
231-
232214
writer.append("()");
233215
}
234216
writer.append(";").eol();
235-
236-
} else {
237-
throw new UnsupportedOperationException("Only Objects and Strings are supported with Jsonb Controller Return Types");
238217
}
239218
}
219+
220+
public static String getBaseType(UType type) {
221+
222+
return Optional.ofNullable(type.param1())
223+
.or(() -> Optional.ofNullable(type.param0()))
224+
.orElseGet(type::full);
225+
}
226+
227+
private static String getBaseType(DeclaredType type) {
228+
final var typeArgs = type.getTypeArguments();
229+
return switch (typeArgs.size()) {
230+
case 1 -> typeArgs.get(0).toString();
231+
232+
case 2 -> typeArgs.get(1).toString();
233+
default -> type.toString();
234+
};
235+
}
236+
237+
private static String createFieldName(String baseType, String fullType) {
238+
final var shortType =
239+
baseType
240+
.substring(baseType.lastIndexOf('.') + 1)
241+
.transform(str -> str.substring(0, 1).toLowerCase() + str.substring(1));
242+
243+
if (fullType.length() <= 13) return shortType;
244+
245+
return switch (fullType.substring(0, 13)) {
246+
case "java.util.Lis" -> "List";
247+
case "java.util.Map" -> "Map";
248+
case "java.util.Set" -> "Set";
249+
default -> shortType;
250+
};
251+
}
240252
}

0 commit comments

Comments
 (0)