Skip to content

Commit 488d492

Browse files
committed
remove support for optional primitives, add support for custom mapped primitives
1 parent 8cb5d7b commit 488d492

File tree

73 files changed

+474
-796
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+474
-796
lines changed

core/src/main/java/net/jbock/coerce/BasicInfo.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,21 @@ public final class BasicInfo {
1212

1313
public final boolean repeatable;
1414

15+
public final boolean optional;
16+
1517
public final TypeMirror returnType;
1618

1719
private final String paramName;
1820

19-
private BasicInfo(boolean repeatable, TypeMirror returnType, String paramName) {
21+
private BasicInfo(boolean repeatable, boolean optional, TypeMirror returnType, String paramName) {
2022
this.repeatable = repeatable;
23+
this.optional = optional;
2124
this.returnType = returnType;
2225
this.paramName = paramName;
2326
}
2427

25-
static BasicInfo create(boolean repeatable, TypeMirror returnType, String paramName) {
26-
return new BasicInfo(repeatable, returnType, snakeToCamel(paramName));
28+
static BasicInfo create(boolean repeatable, boolean optional, TypeMirror returnType, String paramName) {
29+
return new BasicInfo(repeatable, optional, returnType, snakeToCamel(paramName));
2730
}
2831

2932
public String paramName() {

core/src/main/java/net/jbock/coerce/Coercion.java

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,8 @@ public final class Coercion {
2525
// helper.build
2626
private final Optional<CodeBlock> initCollector;
2727

28-
// impl constructor
29-
private final CodeBlock extract;
30-
31-
// impl constructor
32-
private final TypeMirror paramType;
28+
// impl constructor param
29+
private final ParameterSpec constructorParam;
3330

3431
// impl
3532
private final FieldSpec field;
@@ -41,16 +38,14 @@ private Coercion(
4138
Optional<CodeBlock> mapExpr,
4239
CodeBlock initMapper,
4340
Optional<CodeBlock> initCollector,
44-
CodeBlock extract,
45-
TypeMirror paramType,
41+
ParameterSpec constructorParam,
4642
FieldSpec field,
4743
boolean isDefaultCollector) {
4844
this.collectorParam = collectorParam;
4945
this.mapExpr = mapExpr;
5046
this.initMapper = initMapper;
5147
this.initCollector = initCollector;
52-
this.extract = extract;
53-
this.paramType = paramType;
48+
this.constructorParam = constructorParam;
5449
this.field = field;
5550
this.isDefaultCollector = isDefaultCollector;
5651
}
@@ -61,11 +56,12 @@ public static Coercion create(
6156
CodeBlock initMapper,
6257
TypeMirror mapperReturnType,
6358
Optional<CodeBlock> initCollector,
64-
CodeBlock extract,
65-
TypeMirror paramType,
59+
TypeMirror constructorParamType,
6660
BasicInfo basicInfo) {
67-
boolean isDefaultCollector = isDefaultCollector(initCollector, paramType, mapperReturnType);
68-
return new Coercion(collectorParam, mapExpr, initMapper, initCollector, extract, paramType, basicInfo.fieldSpec(), isDefaultCollector);
61+
boolean isDefaultCollector = isDefaultCollector(initCollector, constructorParamType, mapperReturnType);
62+
ParameterSpec constructorParam = ParameterSpec.builder(
63+
TypeName.get(constructorParamType), basicInfo.paramName()).build();
64+
return new Coercion(collectorParam, mapExpr, initMapper, initCollector, constructorParam, basicInfo.fieldSpec(), isDefaultCollector);
6965
}
7066

7167
/**
@@ -86,18 +82,14 @@ public Optional<CodeBlock> initCollector() {
8682
return initCollector;
8783
}
8884

89-
public TypeName paramType() {
90-
return TypeName.get(paramType);
85+
public ParameterSpec constructorParam() {
86+
return constructorParam;
9187
}
9288

9389
public FieldSpec field() {
9490
return field;
9591
}
9692

97-
public CodeBlock extract() {
98-
return extract;
99-
}
100-
10193
public Optional<ParameterSpec> collectorParam() {
10294
if (skipMapCollect()) {
10395
return Optional.empty();

core/src/main/java/net/jbock/coerce/CoercionProvider.java

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ private Coercion handle(
6464
TypeElement collectorClass,
6565
boolean repeatable,
6666
boolean optional) throws TmpException, SearchHintException {
67-
BasicInfo basicInfo = BasicInfo.create(repeatable, sourceMethod.getReturnType(), paramName);
67+
BasicInfo basicInfo = BasicInfo.create(repeatable, optional, sourceMethod.getReturnType(), paramName);
6868
boolean auto = mapperClass == null;
6969
if (repeatable) {
7070
if (auto) {
@@ -87,38 +87,37 @@ private Coercion handleSingleAuto(
8787
boolean optional,
8888
BasicInfo basicInfo) throws TmpException, SearchHintException {
8989
TypeMirror returnType = sourceMethod.getReturnType();
90-
OptionalInfo optionalInfo = findOptionalInfo(returnType, optional);
91-
CoercionFactory enumCoercion = checkEnum(optionalInfo.baseType);
92-
if (enumCoercion != null) {
93-
return enumCoercion.getCoercion(basicInfo, optionalInfo, Optional.empty());
94-
}
95-
CoercionFactory factory = StandardCoercions.get(optionalInfo.baseType);
96-
if (factory == null) {
97-
throw SearchHintException.create("Unknown parameter type. Define a custom mapper.");
98-
}
99-
if (factory.handlesOptionalPrimitive() && !optional) {
90+
Optional<TypeMirror> optionalInfo = findOptionalInfo(returnType, optional);
91+
CoercionFactory factory = findCoercion(optionalInfo.orElse(returnType));
92+
if (optionalInfo.isPresent() && !optional) {
10093
throw TmpException.create("Declare this parameter optional.");
10194
}
102-
if (optional && !factory.handlesOptionalPrimitive() && !optionalInfo.optional) {
103-
throw TmpException.create("Wrap the parameter type in Optional");
95+
if (!optionalInfo.isPresent() && optional) {
96+
throw TmpException.create("Wrap the parameter type in Optional.");
10497
}
10598
return factory.getCoercion(basicInfo, optionalInfo, Optional.empty());
10699
}
107100

108-
// mapper but not repeatable
101+
// simple mapper
109102
private Coercion handleSingle(
110103
ExecutableElement sourceMethod,
111104
String paramName,
112105
TypeElement mapperClass,
113106
BasicInfo basicInfo,
114107
boolean optional) throws TmpException {
108+
TypeMirror returnType = sourceMethod.getReturnType();
115109
ParameterSpec mapperParam = ParameterSpec.builder(TypeName.get(mapperClass.asType()), snakeToCamel(paramName) + "Mapper").build();
116-
OptionalInfo optionalInfo = findOptionalInfo(sourceMethod.getReturnType(), optional);
117-
if (optional && !optionalInfo.optional) {
118-
throw TmpException.create("Wrap the parameter type in Optional");
110+
Optional<TypeMirror> optionalInfo = findOptionalInfo(returnType, optional);
111+
if (optionalInfo.isPresent() && !optional) {
112+
throw TmpException.create("Declare this parameter optional.");
113+
}
114+
if (!optionalInfo.isPresent() && optional) {
115+
throw TmpException.create("Wrap the parameter type in Optional.");
119116
}
120-
MapperClassValidator.checkReturnType(mapperClass, optionalInfo.baseType);
121-
return MapperCoercion.create(optionalInfo, mapperParam, mapperClass.asType(), basicInfo);
117+
TypeMirror boxedReturnType = TypeTool.get().box(returnType);
118+
TypeMirror mapperReturnType = optionalInfo.orElse(boxedReturnType);
119+
MapperClassValidator.checkReturnType(mapperClass, mapperReturnType);
120+
return MapperCoercion.create(mapperReturnType, optionalInfo, Optional.empty(), mapperParam, mapperClass.asType(), basicInfo);
122121
}
123122

124123
// repeatable with mapper
@@ -131,42 +130,47 @@ private Coercion handleRepeatable(
131130
CollectorInfo collectorInfo = collectorInfo(sourceMethod, collectorClass);
132131
MapperClassValidator.checkReturnType(mapperClass, collectorInfo.inputType);
133132
ParameterSpec mapperParam = ParameterSpec.builder(TypeName.get(mapperClass.asType()), snakeToCamel(paramName) + "Mapper").build();
134-
return MapperCoercion.create(OptionalInfo.simple(collectorInfo.inputType), collectorInfo.collectorType(), mapperParam, mapperClass.asType(), basicInfo);
133+
return MapperCoercion.create(collectorInfo.inputType, Optional.empty(), collectorInfo.collectorType(), mapperParam, mapperClass.asType(), basicInfo);
135134
}
136135

137136
// repeatable without mapper
138137
private Coercion handleRepeatableAuto(
139138
ExecutableElement sourceMethod,
140139
TypeElement collectorClass,
141-
BasicInfo basicInfo) throws TmpException {
140+
BasicInfo basicInfo) throws TmpException, SearchHintException {
142141
CollectorInfo collectorInfo = collectorInfo(sourceMethod, collectorClass);
143-
CoercionFactory coercion = StandardCoercions.get(collectorInfo.inputType);
144-
if (coercion == null) {
145-
coercion = checkEnum(collectorInfo.inputType);
142+
CoercionFactory coercion = findCoercion(collectorInfo.inputType);
143+
return coercion.getCoercion(basicInfo, Optional.empty(), collectorInfo.collectorType());
144+
}
145+
146+
private CoercionFactory findCoercion(TypeMirror mirror) throws TmpException, SearchHintException {
147+
CoercionFactory standardCoercion = StandardCoercions.get(mirror);
148+
if (standardCoercion != null) {
149+
return standardCoercion;
146150
}
147-
if (coercion == null || coercion.handlesOptionalPrimitive()) {
148-
throw TmpException.create(String.format("Define a mapper for %s", collectorInfo.inputType));
151+
boolean isEnum = isEnumType(mirror);
152+
if (!isEnum) {
153+
throw SearchHintException.create("Unknown parameter type. Define a custom mapper.");
149154
}
150-
OptionalInfo optionalInfo = OptionalInfo.simple(collectorInfo.inputType);
151-
return coercion.getCoercion(basicInfo, optionalInfo, collectorInfo.collectorType());
155+
return EnumCoercion.create(mirror);
152156
}
153157

154-
private CoercionFactory checkEnum(TypeMirror mirror) throws TmpException {
158+
private boolean isEnumType(TypeMirror mirror) throws TmpException {
155159
TypeTool tool = TypeTool.get();
156160
List<? extends TypeMirror> supertypes = tool.getDirectSupertypes(mirror);
157161
if (supertypes.isEmpty()) {
158162
// not an enum
159-
return null;
163+
return false;
160164
}
161165
TypeMirror superclass = supertypes.get(0);
162166
if (!tool.isSameErasure(superclass, tool.asType(Enum.class))) {
163167
// not an enum
164-
return null;
168+
return false;
165169
}
166170
if (tool.isPrivateType(mirror)) {
167171
throw TmpException.create("The enum may not be private.");
168172
}
169-
return EnumCoercion.create(mirror);
173+
return true;
170174
}
171175

172176
private CollectorInfo collectorInfo(

core/src/main/java/net/jbock/coerce/OptionalInfo.java

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,38 +6,23 @@
66
import java.util.List;
77
import java.util.Optional;
88

9-
public class OptionalInfo {
9+
public final class OptionalInfo {
1010

11-
public final boolean optional;
12-
13-
public final TypeMirror baseType;
14-
15-
private OptionalInfo(boolean optional, TypeMirror baseType) {
16-
this.optional = optional;
17-
this.baseType = baseType;
18-
}
19-
20-
static OptionalInfo simple(TypeMirror baseType) {
21-
return new OptionalInfo(false, baseType);
22-
}
23-
24-
private static OptionalInfo optional(TypeMirror baseType) {
25-
return new OptionalInfo(true, baseType);
26-
}
27-
28-
public static OptionalInfo findOptionalInfo(TypeMirror mirror, boolean optional) {
11+
// Returns empty unless the return type is of the form Optional<?>.
12+
// Note, it can be return emtpy while basicInfo.optional is true,
13+
// if the return type is e.g. OptionalInt.
14+
public static Optional<TypeMirror> findOptionalInfo(TypeMirror mirror, boolean optional) {
2915
if (!optional) {
30-
return OptionalInfo.simple(mirror);
16+
return Optional.empty();
3117
}
3218
TypeTool tool = TypeTool.get();
3319
if (!tool.isSameErasure(mirror, Optional.class)) {
34-
return OptionalInfo.simple(mirror);
20+
return Optional.empty();
3521
}
3622
List<? extends TypeMirror> typeArgs = tool.typeargs(mirror);
3723
if (typeArgs.isEmpty()) {
38-
return OptionalInfo.simple(mirror);
24+
return Optional.empty();
3925
}
40-
return OptionalInfo.optional(typeArgs.get(0));
26+
return Optional.of(typeArgs.get(0));
4127
}
42-
4328
}
Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,21 @@
11
package net.jbock.coerce.hint;
22

3-
import javax.lang.model.element.Name;
4-
import javax.lang.model.element.TypeElement;
5-
import javax.lang.model.type.TypeMirror;
6-
import java.util.Set;
7-
import java.util.stream.Collectors;
3+
import net.jbock.compiler.TypeTool;
84

9-
import static net.jbock.compiler.HierarchyUtil.getTypeTree;
5+
import javax.lang.model.type.TypeMirror;
6+
import java.util.List;
107

118
public class CollectionHint extends Hint {
129

1310
@Override
1411
public String message(TypeMirror type, boolean repeatable) {
15-
Set<String> names = getTypeTree(type).stream()
16-
.map(TypeElement::getQualifiedName)
17-
.map(Name::toString)
18-
.collect(Collectors.toSet());
19-
if (names.contains("java.util.List")) {
12+
if (TypeTool.get().isSameErasure(type, List.class)) {
2013
if (!repeatable) {
2114
return "Declare this parameter repeatable.";
2215
} else {
2316
return "Define a custom mapper.";
2417
}
2518
}
26-
if (names.contains("java.util.Collection") || names.contains("java.util.Map")) {
27-
if (!repeatable) {
28-
return "Declare this parameter repeatable.";
29-
} else {
30-
return "Define a custom collector. Alternatively, use List instead.";
31-
}
32-
}
3319
return null;
3420
}
3521
}

core/src/main/java/net/jbock/coerce/hint/HintProvider.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package net.jbock.coerce.hint;
22

3-
import net.jbock.coerce.OptionalInfo;
4-
53
import javax.lang.model.type.TypeKind;
64
import javax.lang.model.type.TypeMirror;
75
import java.util.Arrays;
@@ -15,6 +13,7 @@ public class HintProvider {
1513

1614
private static final List<Hint> HINTS = Arrays.asList(
1715
new RawCombinatorHint(),
16+
new OptionalPrimitiveHint(),
1817
new CollectionHint(),
1918
new ArrayHint(),
2019
new PrimitiveHint(),
@@ -35,9 +34,9 @@ public Optional<String> findHint(TypeMirror type, boolean repeatable, boolean op
3534
return findHintSimple(type, repeatable);
3635
}
3736
if (optional) {
38-
OptionalInfo optionalInfo = findOptionalInfo(type, true);
39-
if (optionalInfo.optional) {
40-
return findHintSimple(optionalInfo.baseType, repeatable);
37+
Optional<TypeMirror> optionalInfo = findOptionalInfo(type, true);
38+
if (optionalInfo.isPresent()) {
39+
return findHintSimple(optionalInfo.get(), repeatable);
4140
}
4241
}
4342
return findHintSimple(type, repeatable);

core/src/main/java/net/jbock/coerce/hint/OptionalHint.java

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,18 @@
33
import javax.lang.model.element.TypeElement;
44
import javax.lang.model.type.TypeMirror;
55
import java.util.Optional;
6-
import java.util.OptionalDouble;
7-
import java.util.OptionalInt;
8-
import java.util.OptionalLong;
9-
import java.util.Set;
10-
import java.util.stream.Collectors;
11-
import java.util.stream.Stream;
126

137
import static net.jbock.compiler.HierarchyUtil.getTypeTree;
148

159
public class OptionalHint extends Hint {
1610

17-
private static final Set<String> NAMES = Stream.of(
18-
Optional.class,
19-
OptionalInt.class,
20-
OptionalLong.class,
21-
OptionalDouble.class)
22-
.map(Class::getCanonicalName)
23-
.collect(Collectors.toSet());
11+
private static final String NAME = Optional.class.getCanonicalName();
2412

2513
@Override
2614
public String message(TypeMirror type, boolean repeatable) {
2715
for (TypeElement mirror : getTypeTree(type)) {
2816
String qname = mirror.getQualifiedName().toString();
29-
if (NAMES.contains(qname)) {
17+
if (NAME.equals(qname)) {
3018
return "Declare this parameter optional.";
3119
}
3220
}

0 commit comments

Comments
 (0)