Skip to content

Commit f8420dd

Browse files
authored
Merge pull request #7 from h908714124/feature_parseresult_typeclasses
parseresult typeclasses
2 parents 4982562 + cbad406 commit f8420dd

File tree

7 files changed

+115
-70
lines changed

7 files changed

+115
-70
lines changed

core/src/main/java/net/jbock/compiler/Context.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ final class Context {
6060
private final ClassName implType;
6161
private final ClassName tokenizerType;
6262
private final ClassName parseResultType;
63+
private final ClassName successParseResultType;
64+
private final ClassName errorParseResultType;
65+
private final ClassName helpPrintedParseResultType;
6366

6467
private Context(
6568
TypeElement sourceType,
@@ -84,7 +87,10 @@ private Context(
8487
ClassName messagesType,
8588
ClassName implType,
8689
ClassName tokenizerType,
87-
ClassName parseResultType) {
90+
ClassName parseResultType,
91+
ClassName successParseResultType,
92+
ClassName errorParseResultType,
93+
ClassName helpPrintedParseResultType) {
8894
this.sourceType = sourceType;
8995
this.generatedClass = generatedClass;
9096
this.parameters = parameters;
@@ -108,6 +114,9 @@ private Context(
108114
this.implType = implType;
109115
this.tokenizerType = tokenizerType;
110116
this.parseResultType = parseResultType;
117+
this.successParseResultType = successParseResultType;
118+
this.errorParseResultType = errorParseResultType;
119+
this.helpPrintedParseResultType = helpPrintedParseResultType;
111120
}
112121

113122
static Context create(
@@ -133,6 +142,9 @@ static Context create(
133142
ClassName implType = generatedClass.nestedClass(sourceType.getSimpleName() + "Impl");
134143
ClassName tokenizerType = generatedClass.nestedClass("Tokenizer");
135144
ClassName parseResultType = generatedClass.nestedClass("ParseResult");
145+
ClassName successParseResultType = generatedClass.nestedClass("ParsingSuccess");
146+
ClassName errorParseResultType = generatedClass.nestedClass("ParsingFailed");
147+
ClassName helpPrintedParseResultType = generatedClass.nestedClass("HelpPrinted");
136148

137149
return new Context(
138150
sourceType,
@@ -156,7 +168,10 @@ static Context create(
156168
messagesType,
157169
implType,
158170
tokenizerType,
159-
parseResultType);
171+
parseResultType,
172+
successParseResultType,
173+
errorParseResultType,
174+
helpPrintedParseResultType);
160175
}
161176

162177
private static String programName(TypeElement sourceType) {
@@ -235,6 +250,18 @@ ClassName parseResultType() {
235250
return parseResultType;
236251
}
237252

253+
ClassName successParseResultType() {
254+
return successParseResultType;
255+
}
256+
257+
ClassName errorParseResultType() {
258+
return errorParseResultType;
259+
}
260+
261+
ClassName helpPrintedParseResultType() {
262+
return helpPrintedParseResultType;
263+
}
264+
238265
boolean containsType(TypeName typeName) {
239266
for (Param parameter : parameters) {
240267
if (parameter.returnType().equals(typeName)) {

core/src/main/java/net/jbock/compiler/ParseResult.java

Lines changed: 63 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,21 @@
66
import com.squareup.javapoet.TypeName;
77
import com.squareup.javapoet.TypeSpec;
88

9-
import java.util.Optional;
9+
import java.util.Arrays;
10+
import java.util.List;
11+
import java.util.Objects;
1012

1113
import static com.squareup.javapoet.MethodSpec.constructorBuilder;
1214
import static com.squareup.javapoet.MethodSpec.methodBuilder;
1315
import static com.squareup.javapoet.ParameterSpec.builder;
1416
import static com.squareup.javapoet.TypeSpec.classBuilder;
15-
import static java.util.Arrays.asList;
17+
import static javax.lang.model.element.Modifier.ABSTRACT;
1618
import static javax.lang.model.element.Modifier.FINAL;
1719
import static javax.lang.model.element.Modifier.PRIVATE;
1820
import static javax.lang.model.element.Modifier.PUBLIC;
1921
import static javax.lang.model.element.Modifier.STATIC;
22+
import static net.jbock.compiler.Constants.STRING;
2023
import static net.jbock.compiler.Parser.addPublicIfNecessary;
21-
import static net.jbock.compiler.Util.optionalOf;
2224

2325
/**
2426
* Defines the inner class ParseResult.
@@ -27,69 +29,92 @@ final class ParseResult {
2729

2830
private final Context context;
2931

30-
final FieldSpec result;
31-
final FieldSpec success;
32+
private final FieldSpec result;
33+
private final FieldSpec message = FieldSpec.builder(STRING, "message", PRIVATE, FINAL).build();
3234

33-
private ParseResult(Context context, FieldSpec result, FieldSpec success) {
35+
private ParseResult(Context context, FieldSpec result) {
3436
this.context = context;
3537
this.result = result;
36-
this.success = success;
3738
}
3839

3940
static ParseResult create(Context context) {
4041
FieldSpec result = FieldSpec.builder(TypeName.get(context.sourceType.asType()), "result",
4142
PRIVATE, FINAL).build();
42-
FieldSpec success = FieldSpec.builder(TypeName.BOOLEAN, "success",
43-
PRIVATE, FINAL).build();
44-
return new ParseResult(context, result, success);
43+
return new ParseResult(context, result);
4544
}
4645

47-
TypeSpec define() {
46+
List<TypeSpec> define() {
4847
TypeSpec.Builder spec = classBuilder(context.parseResultType())
49-
.addFields(asList(result, success))
50-
.addMethod(addPublicIfNecessary(context, resultMethod()))
51-
.addMethod(addPublicIfNecessary(context, errorMethod()))
52-
.addMethod(addPublicIfNecessary(context, helpPrintedMethod()))
53-
.addMethod(privateConstructor())
54-
.addModifiers(STATIC);
48+
.addMethod(constructorBuilder().addModifiers(PRIVATE).build())
49+
.addModifiers(STATIC, ABSTRACT)
50+
.addJavadoc("This will be a sealed type in the future.\n");
51+
if (context.sourceType.getModifiers().contains(PUBLIC)) {
52+
spec.addModifiers(PUBLIC);
53+
}
54+
return Arrays.asList(spec.build(),
55+
definePrintHelpResult(),
56+
defineErrorResult(),
57+
defineSuccessResult());
58+
}
59+
60+
private TypeSpec definePrintHelpResult() {
61+
TypeSpec.Builder spec = classBuilder(context.helpPrintedParseResultType())
62+
.superclass(context.parseResultType())
63+
.addModifiers(STATIC, FINAL);
5564
if (context.sourceType.getModifiers().contains(PUBLIC)) {
5665
spec.addModifiers(PUBLIC);
5766
}
58-
spec.addModifiers(FINAL);
5967
return spec.build();
6068
}
6169

62-
private MethodSpec.Builder errorMethod() {
63-
return methodBuilder("error")
64-
.addStatement("return !$N", success)
65-
.returns(TypeName.BOOLEAN);
70+
private TypeSpec defineErrorResult() {
71+
ParameterSpec paramMessage = builder(STRING, message.name).build();
72+
TypeSpec.Builder spec = classBuilder(context.errorParseResultType())
73+
.superclass(context.parseResultType())
74+
.addField(message)
75+
.addMethod(constructorBuilder()
76+
.addParameter(paramMessage)
77+
.addStatement("this.$N = $T.requireNonNull($N)", message, Objects.class, paramMessage)
78+
.addModifiers(PRIVATE).build())
79+
.addModifiers(STATIC, FINAL);
80+
if (context.sourceType.getModifiers().contains(PUBLIC)) {
81+
spec.addModifiers(PUBLIC);
82+
}
83+
spec.addMethod(addPublicIfNecessary(context, messageMethod()));
84+
return spec.build();
6685
}
6786

68-
private MethodSpec.Builder helpPrintedMethod() {
69-
return methodBuilder("helpPrinted")
70-
.addStatement("return $N == null && $N", result, success)
71-
.returns(TypeName.BOOLEAN);
87+
private TypeSpec defineSuccessResult() {
88+
TypeSpec.Builder spec = classBuilder(context.successParseResultType())
89+
.superclass(context.parseResultType())
90+
.addField(result)
91+
.addMethod(successConstructor())
92+
.addModifiers(STATIC, FINAL);
93+
if (context.sourceType.getModifiers().contains(PUBLIC)) {
94+
spec.addModifiers(PUBLIC);
95+
}
96+
spec.addMethod(addPublicIfNecessary(context, resultMethod()));
97+
return spec.build();
7298
}
7399

74100
private MethodSpec.Builder resultMethod() {
75101
return methodBuilder("result")
76-
.addStatement("return $T.ofNullable($N)", Optional.class, result)
77-
.returns(optionalOf(TypeName.get(context.sourceType.asType())));
102+
.addStatement("return $N", result)
103+
.returns(TypeName.get(context.sourceType.asType()));
104+
}
105+
106+
private MethodSpec.Builder messageMethod() {
107+
return methodBuilder("message")
108+
.addStatement("return $N", message)
109+
.returns(STRING);
78110
}
79111

80-
private MethodSpec privateConstructor() {
112+
private MethodSpec successConstructor() {
81113
ParameterSpec paramResult = builder(result.type, result.name).build();
82-
ParameterSpec paramSuccess = builder(success.type, success.name).build();
83114
MethodSpec.Builder spec = constructorBuilder()
84-
.addParameter(paramResult)
85-
.addParameter(paramSuccess);
86-
spec.beginControlFlow("if ($N != null && !$N)", paramResult, paramSuccess)
87-
.addComment("sanity check")
88-
.addStatement("throw new $T($S)", IllegalArgumentException.class, "Parsing failed, there can't be a result")
89-
.endControlFlow();
115+
.addParameter(paramResult);
90116
return spec
91-
.addStatement("this.$N = $N", result, paramResult)
92-
.addStatement("this.$N = $N", success, paramSuccess)
117+
.addStatement("this.$N = $T.requireNonNull($N)", result, Objects.class, paramResult)
93118
.addModifiers(PRIVATE)
94119
.build();
95120
}

core/src/main/java/net/jbock/compiler/Parser.java

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ TypeSpec define() {
127127
.addType(RepeatableOptionParser.define(context))
128128
.addType(IndentPrinter.create(context).define())
129129
.addType(Messages.create(context).define())
130-
.addType(parseResult.define())
130+
.addTypes(parseResult.define())
131131
.addField(out)
132132
.addField(err)
133133
.addField(indent)
@@ -264,25 +264,21 @@ private MethodSpec.Builder parseOrExitMethod() {
264264

265265
spec.addStatement("$T $N = parse($N)", result.type, result, args);
266266

267-
// begin error handling
268-
spec.beginControlFlow("if ($N.$N == null)", result, parseResult.result);
267+
spec.beginControlFlow("if ($N instanceof $T)", result, context.successParseResultType())
268+
.addStatement("return (($T) $N).result()", context.successParseResultType(), result)
269+
.endControlFlow();
269270

270-
spec.beginControlFlow("if ($N.$N)", result, parseResult.success)
271-
.addComment("--help was handled")
271+
spec.beginControlFlow("if ($N instanceof $T)", result, context.helpPrintedParseResultType())
272272
.addStatement("$T.exit(0)", System.class)
273273
.endControlFlow();
274-
spec.beginControlFlow("else")
275-
.addComment("parsing failed")
274+
275+
spec.beginControlFlow("if ($N instanceof $T)", result, context.errorParseResultType())
276276
.addStatement("$T.exit($N)", System.class, errorExitCode)
277277
.endControlFlow();
278278

279+
spec.addComment("all cases handled");
279280
spec.addStatement("throw new $T($S)", AssertionError.class, "never thrown");
280281

281-
spec.endControlFlow();
282-
// end error handling
283-
284-
spec.addStatement("return $N.$N", result, parseResult.result);
285-
286282
return spec.addParameter(args)
287283
.returns(TypeName.get(context.sourceType.asType()));
288284
}

core/src/main/java/net/jbock/compiler/Tokenizer.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -294,11 +294,11 @@ private CodeBlock parseMethodTryBlock(
294294
result.type, result, Arrays.class, args);
295295

296296
spec.beginControlFlow("if ($N.isPresent())", result)
297-
.addStatement("return new $T($N.get(), true)", context.parseResultType(), result)
297+
.addStatement("return new $T($N.get())", context.successParseResultType(), result)
298298
.endControlFlow();
299299

300300
spec.addStatement("printUsage()")
301-
.addStatement("return new $T(null, true)", context.parseResultType());
301+
.addStatement("return new $T()", context.helpPrintedParseResultType());
302302
return spec.build();
303303
}
304304

@@ -323,7 +323,7 @@ private CodeBlock parseMethodCatchBlock(ParameterSpec e) {
323323
spec.addStatement("printUsage()");
324324
spec.addStatement("$N.println($N.getMessage())", err, e);
325325
}
326-
spec.addStatement("return new $T(null, false)", context.parseResultType());
326+
spec.addStatement("return new $T($N.getMessage())", context.errorParseResultType(), e);
327327
return spec.build();
328328
}
329329

examples/src/test/java/net/jbock/examples/HelplessArgumentsTest.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
import net.jbock.examples.fixture.TestOutputStream;
44
import org.junit.jupiter.api.Test;
55

6-
import java.util.Optional;
7-
86
import static org.junit.jupiter.api.Assertions.assertEquals;
97
import static org.junit.jupiter.api.Assertions.assertFalse;
108
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -29,26 +27,26 @@ class HelplessArgumentsTest {
2927
@Test
3028
void success0() {
3129
HelplessArguments_Parser.ParseResult opt = HelplessArguments_Parser.create().parse(new String[]{"x"});
32-
assertTrue(opt.result().isPresent());
33-
HelplessArguments args = opt.result().get();
30+
assertTrue(opt instanceof HelplessArguments_Parser.ParsingSuccess);
31+
HelplessArguments args = ((HelplessArguments_Parser.ParsingSuccess) opt).result();
3432
assertEquals("x", args.required());
3533
assertFalse(args.help());
3634
}
3735

3836
@Test
3937
void success1() {
4038
HelplessArguments_Parser.ParseResult opt = HelplessArguments_Parser.create().parse(new String[]{"x", "--help"});
41-
assertTrue(opt.result().isPresent());
42-
HelplessArguments args = opt.result().get();
39+
assertTrue(opt instanceof HelplessArguments_Parser.ParsingSuccess);
40+
HelplessArguments args = ((HelplessArguments_Parser.ParsingSuccess) opt).result();
4341
assertTrue(args.help());
4442
assertEquals("x", args.required());
4543
}
4644

4745
@Test
4846
void success2() {
4947
HelplessArguments_Parser.ParseResult opt = HelplessArguments_Parser.create().parse(new String[]{"--help", "x"});
50-
assertTrue(opt.result().isPresent());
51-
HelplessArguments args = opt.result().get();
48+
assertTrue(opt instanceof HelplessArguments_Parser.ParsingSuccess);
49+
HelplessArguments args = ((HelplessArguments_Parser.ParsingSuccess) opt).result();
5250
assertTrue(args.help());
5351
assertEquals("x", args.required());
5452
}

examples/src/test/java/net/jbock/examples/VariousArgumentsTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class VariousArgumentsTest {
1515

1616
@Test
1717
void bigDecimal() {
18-
Optional<VariousArguments> parsed = VariousArguments_Parser.create().parse(new String[]{
18+
VariousArguments_Parser.ParseResult parsed = VariousArguments_Parser.create().parse(new String[]{
1919
"--file", "/etc/hosts",
2020
"--bigDecimal", "3.14159265358979323846264338327950288419716939937510",
2121
"--bigInteger", "60221407600000000000000",
@@ -40,9 +40,9 @@ void bigDecimal() {
4040
"ISO-8859-1",
4141
"^[abc]*$",
4242
"1970-01-01T00:00:00Z"
43-
}).result();
44-
assertTrue(parsed.isPresent());
45-
VariousArguments args = parsed.get();
43+
});
44+
assertTrue(parsed instanceof VariousArguments_Parser.ParsingSuccess);
45+
VariousArguments args = ((VariousArguments_Parser.ParsingSuccess) parsed).result();
4646
assertEquals(new BigDecimal("3.14159265358979323846264338327950288419716939937510"), args.bigDecimal());
4747
assertEquals(Optional.of(Paths.get("/home")), args.pathPos());
4848
assertEquals(URI.create("http://localhost:8080"), args.uri());

examples/src/test/java/net/jbock/examples/fixture/ParserTestFixture.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import java.lang.reflect.InvocationTargetException;
77
import java.lang.reflect.Method;
88
import java.util.ArrayList;
9-
import java.util.Arrays;
109
import java.util.List;
1110
import java.util.Objects;
1211
import java.util.Optional;
@@ -80,9 +79,9 @@ public Optional<E> parse(String[] args) {
8079
Object parseResult = parseMethod.invoke(builder, new Object[]{args});
8180
Method resultMethod = parseResult.getClass().getDeclaredMethod("result");
8281
resultMethod.setAccessible(true);
83-
return (Optional<E>) resultMethod.invoke(parseResult);
82+
return Optional.of((E) resultMethod.invoke(parseResult));
8483
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
85-
throw new RuntimeException(e);
84+
return Optional.empty();
8685
}
8786
}
8887

0 commit comments

Comments
 (0)