Skip to content

Commit c9c5a08

Browse files
committed
#7 - Support metric parameters
1 parent fae2f90 commit c9c5a08

File tree

9 files changed

+310
-62
lines changed

9 files changed

+310
-62
lines changed

src/main/java/io/dinject/javalin/generator/Constants.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@ class Constants {
1414

1515
static final String IMPORT_PATH_TYPE_CONVERT = "import static io.dinject.controller.PathTypeConversion.*;";
1616

17-
static String WEB_ROUTES = "io.dinject.controller.WebRoutes";
17+
static final String IMPORT_CONTROLLER = "io.dinject.controller.*";
1818

1919
}

src/main/java/io/dinject/javalin/generator/ControllerReader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class ControllerReader {
3939
}
4040
importTypes.add(Constants.SINGLETON);
4141
importTypes.add(Constants.API_BUILDER);
42-
importTypes.add(Constants.WEB_ROUTES);
42+
importTypes.add(Constants.IMPORT_CONTROLLER);
4343
importTypes.add(beanType.getQualifiedName().toString());
4444
}
4545

src/main/java/io/dinject/javalin/generator/ElementReader.java

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010

1111
import javax.lang.model.element.Element;
1212
import javax.lang.model.element.TypeElement;
13-
import java.util.Collections;
14-
import java.util.Set;
1513

1614
class ElementReader {
1715

@@ -23,6 +21,7 @@ class ElementReader {
2321

2422
private String paramName;
2523
private ParamType paramType;
24+
private boolean impliedParamType;
2625
private String paramDefault;
2726
private String docComment;
2827

@@ -82,6 +81,7 @@ private void readAnnotations(Element element, ParamType defaultType) {
8281
}
8382
if (paramType == null) {
8483
this.paramType = defaultType;
84+
this.impliedParamType = true;
8585
}
8686
}
8787

@@ -117,16 +117,6 @@ private String shortType() {
117117
}
118118
}
119119

120-
private String derivePathParam(Set<String> pathParams) {
121-
if (pathParams.contains(varName)) {
122-
return varName;
123-
}
124-
if (pathParams.contains(snakeName)) {
125-
return snakeName;
126-
}
127-
return null;
128-
}
129-
130120
void addImports(ControllerReader bean) {
131121
if (typeHandler != null) {
132122
String importType = typeHandler.getImportType();
@@ -146,7 +136,7 @@ void writeParamName(Append writer) {
146136
}
147137
}
148138

149-
void writeCtxGet(Append writer, Set<String> pathParams) {
139+
void writeCtxGet(Append writer, PathSegments segments) {
150140

151141
if (isJavalinContext()) {
152142
// no conversion for this parameter
@@ -155,17 +145,17 @@ void writeCtxGet(Append writer, Set<String> pathParams) {
155145

156146
String shortType = shortType();
157147
writer.append(" %s %s = ", shortType, varName);
158-
if (setValue(writer, pathParams, shortType)) {
148+
if (setValue(writer, segments, shortType)) {
159149
writer.append(";").eol();
160150
}
161151
}
162152

163153
void setValue(Append writer) {
164154
String shortType = shortType();
165-
setValue(writer, Collections.emptySet(), shortType);
155+
setValue(writer, PathSegments.EMPTY, shortType);
166156
}
167157

168-
private boolean setValue(Append writer, Set<String> pathParams, String shortType) {
158+
private boolean setValue(Append writer, PathSegments segments, String shortType) {
169159

170160
if (ParamType.FORM == paramType) {
171161
writeForm(writer, shortType, varName, ParamType.FORMPARAM);
@@ -176,26 +166,38 @@ private boolean setValue(Append writer, Set<String> pathParams, String shortType
176166
return false;
177167
}
178168

179-
// path parameters are expected to be not nullable
180-
// ... with query parameters nullable
181-
String pathParameter = derivePathParam(pathParams);
182-
String asMethod = (typeHandler == null) ? null : (pathParameter != null) ? typeHandler.asMethod() : typeHandler.toMethod();
169+
if (impliedParamType) {
170+
PathSegments.Segment segment = segments.segment(varName);
171+
if (segment != null) {
172+
// path or metric parameter
173+
boolean requiredParam = segment.isRequired(varName);
174+
String asMethod = (typeHandler == null) ? null : (requiredParam) ? typeHandler.asMethod() : typeHandler.toMethod();
175+
176+
if (asMethod != null) {
177+
writer.append(asMethod);
178+
}
179+
segment.writeGetVal(writer, varName);
180+
if (asMethod != null) {
181+
writer.append(")");
182+
}
183+
return true;
184+
}
185+
}
186+
187+
String asMethod = (typeHandler == null) ? null : typeHandler.toMethod();
183188

184189
if (asMethod != null) {
185190
writer.append(asMethod);
186191
}
187-
if (pathParameter != null) {
188-
writer.append("ctx.pathParam(\"%s\")", pathParameter);
192+
193+
if (typeHandler == null) {
194+
// assuming this is a body (POST, PATCH)
195+
writer.append("ctx.bodyAsClass(%s.class)", shortType);
189196
} else {
190-
if (typeHandler == null) {
191-
// assuming this is a body (POST, PATCH)
192-
writer.append("ctx.bodyAsClass(%s.class)", shortType);
197+
if (hasParamDefault()) {
198+
writer.append("ctx.%s(\"%s\",\"%s\")", paramType, paramName, paramDefault);
193199
} else {
194-
if (hasParamDefault()) {
195-
writer.append("ctx.%s(\"%s\",\"%s\")", paramType, paramName, paramDefault);
196-
} else {
197-
writer.append("ctx.%s(\"%s\")", paramType, paramName);
198-
}
200+
writer.append("ctx.%s(\"%s\")", paramType, paramName);
199201
}
200202
}
201203

src/main/java/io/dinject/javalin/generator/MethodParam.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package io.dinject.javalin.generator;
22

33
import javax.lang.model.element.VariableElement;
4-
import java.util.Set;
54

65
class MethodParam {
76

@@ -11,9 +10,8 @@ class MethodParam {
1110
this.elementParam = new ElementReader(param, ctx, defaultParamType);
1211
}
1312

14-
void buildCtxGet(Append writer, Set<String> pathParams) {
15-
16-
elementParam.writeCtxGet(writer, pathParams);
13+
void buildCtxGet(Append writer, PathSegments segments) {
14+
elementParam.writeCtxGet(writer, segments);
1715
}
1816

1917
void addImports(ControllerReader bean) {

src/main/java/io/dinject/javalin/generator/MethodReader.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import javax.lang.model.element.VariableElement;
1212
import java.util.ArrayList;
1313
import java.util.List;
14-
import java.util.Set;
1514

1615
import static io.dinject.javalin.generator.Constants.JAVALIN_ROLES;
1716

@@ -70,12 +69,18 @@ void addRoute(Append writer) {
7069
if (webMethod != null) {
7170

7271
String fullPath = Util.combinePath(beanPath, webMethodPath);
73-
Set<String> pathParams = Util.pathParams(fullPath);
72+
PathSegments segments = PathSegments.parse(fullPath);
7473

75-
writer.append(" ApiBuilder.%s(\"%s\", ctx -> {", webMethod.name().toLowerCase(), fullPath).eol();
74+
writer.append(" ApiBuilder.%s(\"%s\", ctx -> {", webMethod.name().toLowerCase(), segments.fullPath()).eol();
7675
writer.append(" ctx.status(%s);", httpStatusCode()).eol();
76+
77+
List<PathSegments.Segment> metricSegments = segments.metricSegments();
78+
for (PathSegments.Segment metricSegment : metricSegments) {
79+
metricSegment.writeCreateSegment(writer);
80+
}
81+
7782
for (MethodParam param : params) {
78-
param.buildCtxGet(writer, pathParams);
83+
param.buildCtxGet(writer, segments);
7984
}
8085
writer.append(" ");
8186

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
package io.dinject.javalin.generator;
2+
3+
import java.util.ArrayList;
4+
import java.util.Arrays;
5+
import java.util.Collections;
6+
import java.util.HashSet;
7+
import java.util.LinkedHashSet;
8+
import java.util.List;
9+
import java.util.Set;
10+
11+
class PathSegments {
12+
13+
static final PathSegments EMPTY = new PathSegments("", Collections.emptySet());
14+
15+
static PathSegments parse(String fullPath) {
16+
17+
Set<Segment> segments = new LinkedHashSet<>();
18+
19+
StringBuilder path = new StringBuilder();
20+
21+
for (String section : fullPath.split("/")) {
22+
if (!section.isEmpty()) {
23+
path.append("/");
24+
if (section.startsWith(":")) {
25+
Segment segment = createSegment(section.substring(1));
26+
segments.add(segment);
27+
path.append(segment.path(section));
28+
29+
} else {
30+
path.append(section);
31+
}
32+
}
33+
}
34+
35+
return new PathSegments(path.toString(), segments);
36+
}
37+
38+
private static Segment createSegment(String val) {
39+
40+
String[] metricSplit = val.split(";");
41+
if (metricSplit.length == 1) {
42+
return new Segment(metricSplit[0]);
43+
}
44+
45+
Set<String> metrics = new HashSet<>(Arrays.asList(metricSplit).subList(1, metricSplit.length));
46+
return new Segment(metricSplit[0], metrics);
47+
}
48+
49+
private final String fullPath;
50+
51+
private final Set<Segment> segments;
52+
53+
private final List<Segment> withMetrics = new ArrayList<>();
54+
55+
private final Set<String> allNames = new HashSet<>();
56+
57+
private PathSegments(String fullPath, Set<Segment> segments) {
58+
this.fullPath = fullPath;
59+
this.segments = segments;
60+
for (Segment segment : segments) {
61+
segment.addNames(allNames);
62+
if (segment.hasMetrics()) {
63+
withMetrics.add(segment);
64+
}
65+
}
66+
}
67+
68+
69+
boolean contains(String varName) {
70+
return allNames.contains(varName);
71+
}
72+
73+
List<Segment> metricSegments() {
74+
return withMetrics;
75+
}
76+
77+
Segment segment(String varName) {
78+
79+
for (Segment segment : segments) {
80+
if (segment.isPathParameter(varName)) {
81+
return segment;
82+
}
83+
}
84+
return null;
85+
}
86+
87+
String fullPath() {
88+
return fullPath;
89+
}
90+
91+
static class Segment {
92+
93+
private final String name;
94+
95+
/**
96+
* Metric keys.
97+
*/
98+
private final Set<String> metrics;
99+
100+
/**
101+
* Variable names the metrics map to (Java method param names).
102+
*/
103+
private final Set<String> metricVarNames;
104+
105+
Segment(String name) {
106+
this.name = name;
107+
this.metrics = null;
108+
this.metricVarNames = null;
109+
}
110+
111+
Segment(String name, Set<String> metrics) {
112+
this.name = name;
113+
this.metrics = metrics;
114+
this.metricVarNames = new HashSet<>();
115+
for (String key : metrics) {
116+
metricVarNames.add(combine(name, key));
117+
}
118+
}
119+
120+
void addNames(Set<String> allNames) {
121+
allNames.add(name);
122+
}
123+
124+
boolean hasMetrics() {
125+
return metrics != null && !metrics.isEmpty();
126+
}
127+
128+
private String combine(String name, String key) {
129+
return name + Character.toUpperCase(key.charAt(0)) + key.substring(1);
130+
}
131+
132+
Set<String> metrics() {
133+
return metrics;
134+
}
135+
136+
String name() {
137+
return name;
138+
}
139+
140+
boolean isPathParameter(String varName) {
141+
return name.equals(varName) || (metrics != null && (metricVarNames.contains(varName) || metrics.contains(varName)));
142+
}
143+
144+
/**
145+
* Reading the value from a segment (rather than directly from pathParam).
146+
*/
147+
void writeGetVal(Append writer, String varName) {
148+
if (!hasMetrics()) {
149+
writer.append("ctx.pathParam(\"%s\")", name);
150+
151+
} else {
152+
writer.append("%s_segment.", name);
153+
if (name.equals(varName)) {
154+
writer.append("val()");
155+
} else {
156+
writer.append("metric(\"%s\")", metricKey(varName));
157+
}
158+
}
159+
}
160+
161+
private String metricKey(String varName) {
162+
163+
if (!varName.startsWith(name)) {
164+
return varName;
165+
}
166+
167+
String key = varName.substring(name.length());
168+
return Character.toLowerCase(key.charAt(0)) + key.substring(1);
169+
}
170+
171+
void writeCreateSegment(Append writer) {
172+
writer.append(" PathSegment %s_segment = PathSegment.of(ctx.pathParam(\"%s_segment\"));", name, name).eol();
173+
}
174+
175+
boolean isRequired(String varName) {
176+
return name.equals(varName);
177+
}
178+
179+
String path(String section) {
180+
if (!hasMetrics()) {
181+
return section;
182+
}
183+
return ":" + name + "_segment";
184+
}
185+
}
186+
}

src/main/java/io/dinject/javalin/generator/Util.java

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,6 @@ static String combinePath(String beanPath, String webMethodPath) {
3030
return sb.toString();
3131
}
3232

33-
static Set<String> pathParams(String fullPath) {
34-
35-
Set<String> paramNames = new LinkedHashSet<>();
36-
for (String section : fullPath.split("/")) {
37-
if (section.startsWith(":")) {
38-
paramNames.add(section.substring(1));
39-
}
40-
}
41-
return paramNames;
42-
}
43-
4433
static String shortName(String fullType) {
4534
int p = fullType.lastIndexOf('.');
4635
if (p == -1) {

0 commit comments

Comments
 (0)