Skip to content

Commit 2ff451e

Browse files
authored
Merge pull request #39 from andyglow/adt-methods
introduce ADT methods
2 parents e9f235e + 22c62ad commit 2ff451e

15 files changed

Lines changed: 687 additions & 113 deletions

File tree

dataenum-processor/src/main/java/com/spotify/dataenum/processor/DataEnumProcessor.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,24 @@
3333
import com.squareup.javapoet.ArrayTypeName;
3434
import com.squareup.javapoet.JavaFile;
3535
import com.squareup.javapoet.TypeSpec;
36+
import com.sun.source.util.Trees;
3637
import java.io.IOException;
3738
import java.util.Collections;
3839
import java.util.Set;
39-
import javax.annotation.processing.AbstractProcessor;
40-
import javax.annotation.processing.Filer;
41-
import javax.annotation.processing.Messager;
42-
import javax.annotation.processing.RoundEnvironment;
40+
import javax.annotation.processing.*;
4341
import javax.lang.model.SourceVersion;
4442
import javax.lang.model.element.Element;
4543
import javax.lang.model.element.TypeElement;
4644
import javax.tools.Diagnostic;
4745

4846
public class DataEnumProcessor extends AbstractProcessor {
47+
private Trees trees;
48+
49+
@Override
50+
public synchronized void init(ProcessingEnvironment processingEnv) {
51+
super.init(processingEnv);
52+
this.trees = Trees.instance(processingEnv);
53+
}
4954

5055
@Override
5156
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
@@ -58,7 +63,7 @@ public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnv
5863
for (Element element : roundEnvironment.getElementsAnnotatedWith(DataEnum.class)) {
5964
try {
6065

61-
Spec spec = SpecParser.parse(element, processingEnv);
66+
Spec spec = SpecParser.parse(element, new ProcessingContext(processingEnv));
6267
if (spec == null) {
6368
continue;
6469
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.spotify.dataenum.processor;
2+
3+
import com.spotify.dataenum.dataenum_case;
4+
import com.sun.source.util.Trees;
5+
import javax.annotation.processing.ProcessingEnvironment;
6+
import javax.lang.model.type.TypeMirror;
7+
import javax.lang.model.util.Elements;
8+
import javax.lang.model.util.Types;
9+
10+
public final class ProcessingContext {
11+
public final ProcessingEnvironment env;
12+
public final Trees trees;
13+
public final TypeMirror dataenum_class_element;
14+
15+
public ProcessingContext(ProcessingEnvironment env) {
16+
this.env = env;
17+
this.trees = Trees.instance(env);
18+
19+
Types types = env.getTypeUtils();
20+
Elements elements = env.getElementUtils();
21+
this.dataenum_class_element =
22+
elements.getTypeElement(dataenum_case.class.getCanonicalName()).asType();
23+
}
24+
}

dataenum-processor/src/main/java/com/spotify/dataenum/processor/data/OutputSpec.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,12 @@ public class OutputSpec extends Spec {
3131
private final Iterable<OutputValue> outputValues;
3232

3333
public OutputSpec(Spec input, ClassName outputClass, Iterable<OutputValue> outputValues) {
34-
super(input.specClass(), input.typeVariables(), input.superInterfaces(), input.values());
34+
super(
35+
input.specClass(),
36+
input.typeVariables(),
37+
input.superInterfaces(),
38+
input.values(),
39+
input.methods());
3540
this.outputClass = outputClass;
3641
this.outputValues = outputValues;
3742
}

dataenum-processor/src/main/java/com/spotify/dataenum/processor/data/Spec.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import com.spotify.dataenum.processor.util.Iterables;
2323
import com.squareup.javapoet.ClassName;
24+
import com.squareup.javapoet.MethodSpec;
2425
import com.squareup.javapoet.TypeVariableName;
2526

2627
/**
@@ -34,16 +35,19 @@ public class Spec {
3435
private final Iterable<TypeVariableName> typeVariables;
3536
private final Iterable<ClassName> interfaces;
3637
private final Iterable<Value> values;
38+
private final Iterable<MethodSpec> methods;
3739

3840
public Spec(
3941
ClassName specClass,
4042
Iterable<TypeVariableName> typeVariables,
4143
Iterable<ClassName> interfaces,
42-
Iterable<Value> values) {
44+
Iterable<Value> values,
45+
Iterable<MethodSpec> methods) {
4346
this.specClass = specClass;
4447
this.typeVariables = typeVariables;
4548
this.interfaces = interfaces;
4649
this.values = values;
50+
this.methods = methods;
4751
}
4852

4953
public ClassName specClass() {
@@ -65,4 +69,8 @@ public boolean hasTypeVariables() {
6569
public Iterable<Value> values() {
6670
return values;
6771
}
72+
73+
public Iterable<MethodSpec> methods() {
74+
return methods;
75+
}
6876
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package com.spotify.dataenum.processor.generator.method;
2+
3+
import com.squareup.javapoet.*;
4+
import com.sun.source.tree.MethodTree;
5+
import com.sun.source.util.TreePathScanner;
6+
import com.sun.source.util.Trees;
7+
import java.util.concurrent.atomic.AtomicReference;
8+
import java.util.function.Consumer;
9+
import java.util.function.Function;
10+
import java.util.stream.Collectors;
11+
import java.util.stream.Stream;
12+
import javax.lang.model.element.AnnotationMirror;
13+
import javax.lang.model.element.ElementKind;
14+
import javax.lang.model.element.ExecutableElement;
15+
import javax.lang.model.element.Modifier;
16+
17+
public final class MethodMethods {
18+
private MethodMethods() {}
19+
20+
public static MethodSpec.Builder builderFrom(
21+
ExecutableElement el,
22+
Function<Stream<Modifier>, Stream<Modifier>> adjustModifiers,
23+
Function<Stream<? extends AnnotationMirror>, Stream<? extends AnnotationMirror>>
24+
adjustAnnotations) {
25+
return MethodSpec.methodBuilder(el.getSimpleName().toString())
26+
.addModifiers(adjustModifiers.apply(el.getModifiers().stream()).collect(Collectors.toSet()))
27+
.addAnnotations(
28+
adjustAnnotations
29+
.apply(el.getAnnotationMirrors().stream())
30+
.map(AnnotationSpec::get)
31+
.collect(Collectors.toList()))
32+
.addTypeVariables(
33+
el.getTypeParameters().stream().map(TypeVariableName::get).collect(Collectors.toList()))
34+
.returns(TypeName.get(el.getReturnType()))
35+
.addParameters(
36+
el.getParameters().stream().map(ParameterSpec::get).collect(Collectors.toList()))
37+
.varargs(el.isVarArgs())
38+
.addExceptions(
39+
el.getThrownTypes().stream().map(TypeName::get).collect(Collectors.toList()));
40+
}
41+
42+
public static CodeBlock codeBlockFrom(ExecutableElement el, Trees trees) {
43+
final MethodTree methodTree = MethodLookup.lookupTree(el, trees);
44+
return methodTree.getBody().getStatements().stream()
45+
.map(x -> CodeBlock.of(x.toString()))
46+
.reduce(CodeBlock.of(""), (a, b) -> a.toBuilder().add(b).build());
47+
}
48+
49+
private static class MethodLookup extends TreePathScanner<Void, Void> {
50+
51+
private final Consumer<MethodTree> onMethod;
52+
53+
private MethodLookup(Consumer<MethodTree> onMethod) {
54+
this.onMethod = onMethod;
55+
}
56+
57+
public static MethodTree lookupTree(ExecutableElement methodElement, Trees trees) {
58+
assert methodElement.getKind() == ElementKind.METHOD;
59+
60+
AtomicReference<MethodTree> methodRef = new AtomicReference<>();
61+
new MethodLookup(methodRef::set).scan(trees.getPath(methodElement), null);
62+
MethodTree method = methodRef.get();
63+
assert method != null;
64+
65+
return method;
66+
}
67+
68+
@Override
69+
public Void visitMethod(MethodTree methodTree, Void v) {
70+
this.onMethod.accept(methodTree);
71+
return super.visitMethod(methodTree, v);
72+
}
73+
}
74+
}

dataenum-processor/src/main/java/com/spotify/dataenum/processor/generator/spec/SpecTypeFactory.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ public static TypeSpec create(
9696
enumBuilder.addMethod(mapMethods.createAbstractFoldMethod());
9797
}
9898

99+
enumBuilder.addMethods(spec.methods());
100+
99101
return enumBuilder.build();
100102
}
101103
}

0 commit comments

Comments
 (0)