annotations() {
93 | return annotations;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/dataenum-processor/src/main/java/com/spotify/dataenum/processor/data/Parameter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * -\-\-
3 | * DataEnum
4 | * --
5 | * Copyright (c) 2017 Spotify AB
6 | * --
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * -/-/-
19 | */
20 | package com.spotify.dataenum.processor.data;
21 |
22 | import com.squareup.javapoet.TypeName;
23 |
24 | public class Parameter {
25 | private final String name;
26 | private final TypeName type;
27 | private final boolean nullable;
28 | private final boolean redacted;
29 | private final boolean isEnum;
30 |
31 | public Parameter(String name, TypeName type, boolean nullable, boolean redacted, boolean isEnum) {
32 | this.name = name;
33 | this.type = type;
34 | this.nullable = nullable;
35 | this.redacted = redacted;
36 | this.isEnum = isEnum;
37 | }
38 |
39 | public String name() {
40 | return name;
41 | }
42 |
43 | public TypeName type() {
44 | return type;
45 | }
46 |
47 | public boolean canBeNull() {
48 | return nullable;
49 | }
50 |
51 | public boolean redacted() {
52 | return redacted;
53 | }
54 |
55 | public boolean isEnum() {
56 | return isEnum;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/dataenum-processor/src/main/java/com/spotify/dataenum/processor/data/Spec.java:
--------------------------------------------------------------------------------
1 | /*
2 | * -\-\-
3 | * DataEnum
4 | * --
5 | * Copyright (c) 2017 Spotify AB
6 | * --
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * -/-/-
19 | */
20 | package com.spotify.dataenum.processor.data;
21 |
22 | import com.spotify.dataenum.processor.util.Iterables;
23 | import com.squareup.javapoet.ClassName;
24 | import com.squareup.javapoet.MethodSpec;
25 | import com.squareup.javapoet.TypeVariableName;
26 |
27 | /**
28 | * Represents the data represented in a 'MyValue_spec' class.
29 | *
30 | * Contains a reference to the source _spec and its type variable, as well as all the possible
31 | * values.
32 | */
33 | public class Spec {
34 | private final ClassName specClass;
35 | private final Iterable typeVariables;
36 | private final Iterable interfaces;
37 | private final Iterable values;
38 | private final Iterable methods;
39 |
40 | public Spec(
41 | ClassName specClass,
42 | Iterable typeVariables,
43 | Iterable interfaces,
44 | Iterable values,
45 | Iterable methods) {
46 | this.specClass = specClass;
47 | this.typeVariables = typeVariables;
48 | this.interfaces = interfaces;
49 | this.values = values;
50 | this.methods = methods;
51 | }
52 |
53 | public ClassName specClass() {
54 | return specClass;
55 | }
56 |
57 | public Iterable typeVariables() {
58 | return typeVariables;
59 | }
60 |
61 | public Iterable superInterfaces() {
62 | return interfaces;
63 | }
64 |
65 | public boolean hasTypeVariables() {
66 | return !Iterables.isEmpty(typeVariables());
67 | }
68 |
69 | public Iterable values() {
70 | return values;
71 | }
72 |
73 | public Iterable methods() {
74 | return methods;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/dataenum-processor/src/main/java/com/spotify/dataenum/processor/data/Value.java:
--------------------------------------------------------------------------------
1 | /*
2 | * -\-\-
3 | * DataEnum
4 | * --
5 | * Copyright (c) 2017 Spotify AB
6 | * --
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * -/-/-
19 | */
20 | package com.spotify.dataenum.processor.data;
21 |
22 | import com.spotify.dataenum.processor.util.Iterables;
23 | import com.squareup.javapoet.AnnotationSpec;
24 | import javax.annotation.Nullable;
25 |
26 | /** Represents one of the possible values of a dataenum spec. */
27 | public class Value {
28 | private final String simpleName;
29 | @Nullable private final String javadoc;
30 | private final Iterable parameters;
31 | private final Iterable annotations;
32 |
33 | public Value(
34 | String simpleName,
35 | String javadoc,
36 | Iterable parameters,
37 | Iterable annotations) {
38 | this.simpleName = simpleName;
39 | this.javadoc = javadoc;
40 | this.parameters = parameters;
41 | this.annotations = annotations;
42 | }
43 |
44 | public String name() {
45 | return simpleName;
46 | }
47 |
48 | @Nullable
49 | public String javadoc() {
50 | return javadoc;
51 | }
52 |
53 | public Iterable parameters() {
54 | return parameters;
55 | }
56 |
57 | public boolean hasParameters() {
58 | return !Iterables.isEmpty(parameters());
59 | }
60 |
61 | public Iterable annotations() {
62 | return annotations;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/dataenum-processor/src/main/java/com/spotify/dataenum/processor/generator/data/OutputSpecFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * -\-\-
3 | * DataEnum
4 | * --
5 | * Copyright (c) 2017 Spotify AB
6 | * --
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * -/-/-
19 | */
20 | package com.spotify.dataenum.processor.generator.data;
21 |
22 | import com.spotify.dataenum.processor.data.OutputSpec;
23 | import com.spotify.dataenum.processor.data.OutputValue;
24 | import com.spotify.dataenum.processor.data.Spec;
25 | import com.spotify.dataenum.processor.data.Value;
26 | import com.spotify.dataenum.processor.parser.ParserException;
27 | import com.squareup.javapoet.ClassName;
28 | import java.util.ArrayList;
29 | import java.util.List;
30 |
31 | public final class OutputSpecFactory {
32 |
33 | private OutputSpecFactory() {}
34 |
35 | private static final String SUFFIX = "_dataenum";
36 |
37 | public static OutputSpec create(Spec spec) throws ParserException {
38 | ClassName specClass = spec.specClass();
39 |
40 | ClassName outputClass = toOutputClassName(specClass);
41 |
42 | List values = new ArrayList<>();
43 | for (Value value : spec.values()) {
44 | values.add(OutputValueFactory.create(value, outputClass, spec));
45 | }
46 |
47 | return new OutputSpec(spec, outputClass, values);
48 | }
49 |
50 | static boolean isSpecClassName(ClassName specClassName) {
51 | return specClassName.simpleName().endsWith(SUFFIX);
52 | }
53 |
54 | static ClassName toOutputClassName(ClassName specClassName) throws ParserException {
55 | String packageName = specClassName.packageName();
56 | String name = specClassName.simpleName();
57 |
58 | if (!isSpecClassName(specClassName)) {
59 | throw new ParserException(
60 | String.format(
61 | "Bad name for DataEnum interface! Name must end with '%s', found: %s", SUFFIX, name));
62 | }
63 |
64 | String nameWithoutSuffix = name.substring(0, name.length() - SUFFIX.length());
65 | return ClassName.get(packageName, nameWithoutSuffix);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/dataenum-processor/src/main/java/com/spotify/dataenum/processor/generator/data/OutputValueFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * -\-\-
3 | * DataEnum
4 | * --
5 | * Copyright (c) 2017 Spotify AB
6 | * --
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * -/-/-
19 | */
20 | package com.spotify.dataenum.processor.generator.data;
21 |
22 | import static com.spotify.dataenum.processor.generator.data.OutputSpecFactory.isSpecClassName;
23 | import static com.spotify.dataenum.processor.generator.data.OutputSpecFactory.toOutputClassName;
24 |
25 | import com.spotify.dataenum.processor.data.OutputValue;
26 | import com.spotify.dataenum.processor.data.Parameter;
27 | import com.spotify.dataenum.processor.data.Spec;
28 | import com.spotify.dataenum.processor.data.Value;
29 | import com.spotify.dataenum.processor.parser.ParserException;
30 | import com.squareup.javapoet.ArrayTypeName;
31 | import com.squareup.javapoet.ClassName;
32 | import com.squareup.javapoet.ParameterizedTypeName;
33 | import com.squareup.javapoet.TypeName;
34 | import com.squareup.javapoet.TypeVariableName;
35 | import java.util.ArrayList;
36 | import java.util.LinkedHashSet;
37 | import java.util.List;
38 | import java.util.Set;
39 |
40 | final class OutputValueFactory {
41 |
42 | private OutputValueFactory() {}
43 |
44 | static OutputValue create(Value value, ClassName specOutputClass, Spec spec)
45 | throws ParserException {
46 | ClassName outputClass = specOutputClass.nestedClass(value.name());
47 | Iterable typeVariables = getTypeVariables(value, spec.typeVariables());
48 |
49 | List parameters = new ArrayList<>();
50 | for (Parameter parameter : value.parameters()) {
51 | parameters.add(parameterWithoutDataEnumSuffix(parameter));
52 | }
53 |
54 | return new OutputValue(
55 | outputClass, value.name(), value.javadoc(), parameters, typeVariables, value.annotations());
56 | }
57 |
58 | private static Parameter parameterWithoutDataEnumSuffix(Parameter parameter)
59 | throws ParserException {
60 | return new Parameter(
61 | parameter.name(),
62 | typeWithoutDataEnumSuffixes(parameter.type()),
63 | parameter.canBeNull(),
64 | parameter.redacted(),
65 | parameter.isEnum());
66 | }
67 |
68 | private static TypeName typeWithoutDataEnumSuffixes(TypeName typeName) throws ParserException {
69 | if (typeName instanceof ParameterizedTypeName) {
70 | ParameterizedTypeName paramTypeName = (ParameterizedTypeName) typeName;
71 |
72 | ClassName outputClassName;
73 | if (isSpecClassName(paramTypeName.rawType)) {
74 | outputClassName = toOutputClassName(paramTypeName.rawType);
75 | } else {
76 | outputClassName = paramTypeName.rawType;
77 | }
78 |
79 | TypeName[] typeArgumentsArr = new TypeName[paramTypeName.typeArguments.size()];
80 | for (int i = 0; i < typeArgumentsArr.length; i++) {
81 | typeArgumentsArr[i] = typeWithoutDataEnumSuffixes(paramTypeName.typeArguments.get(i));
82 | }
83 |
84 | return ParameterizedTypeName.get(outputClassName, typeArgumentsArr);
85 | }
86 |
87 | if (typeName instanceof ClassName) {
88 | ClassName className = (ClassName) typeName;
89 | if (isSpecClassName(className)) {
90 | return toOutputClassName(className);
91 | }
92 | return className;
93 | }
94 |
95 | return typeName;
96 | }
97 |
98 | private static Iterable getTypeVariables(
99 | Value value, Iterable typeVariables) {
100 | Set output = new LinkedHashSet<>();
101 | for (TypeVariableName typeVariable : typeVariables) {
102 | for (Parameter parameter : value.parameters()) {
103 | if (typeNeedsTypeVariable(parameter.type(), typeVariable)) {
104 | output.add(typeVariable);
105 | }
106 | }
107 | }
108 | return output;
109 | }
110 |
111 | private static boolean typeNeedsTypeVariable(TypeName type, TypeVariableName typeVariable) {
112 | if (typeVariable.equals(type)) {
113 | return true;
114 | }
115 |
116 | if (type instanceof ParameterizedTypeName) {
117 | ParameterizedTypeName parameterized = ((ParameterizedTypeName) type);
118 | for (TypeName typeArgument : parameterized.typeArguments) {
119 | if (typeVariable.equals(typeArgument)) {
120 | return true;
121 | }
122 | if (typeNeedsTypeVariable(typeArgument, typeVariable)) {
123 | return true;
124 | }
125 | }
126 | }
127 |
128 | if (type instanceof ArrayTypeName) {
129 | ArrayTypeName arrayType = (ArrayTypeName) type;
130 | if (typeVariable.equals(arrayType.componentType)) {
131 | return true;
132 | }
133 | }
134 | return false;
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/dataenum-processor/src/main/java/com/spotify/dataenum/processor/generator/match/MapMethods.java:
--------------------------------------------------------------------------------
1 | /*
2 | * -\-\-
3 | * DataEnum
4 | * --
5 | * Copyright (c) 2017 Spotify AB
6 | * --
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * -/-/-
19 | */
20 | package com.spotify.dataenum.processor.generator.match;
21 |
22 | import com.spotify.dataenum.function.Function;
23 | import com.spotify.dataenum.processor.data.OutputValue;
24 | import com.spotify.dataenum.processor.parser.ParserException;
25 | import com.squareup.javapoet.ClassName;
26 | import com.squareup.javapoet.MethodSpec;
27 | import com.squareup.javapoet.ParameterSpec;
28 | import com.squareup.javapoet.ParameterizedTypeName;
29 | import com.squareup.javapoet.TypeName;
30 | import com.squareup.javapoet.TypeVariableName;
31 | import javax.annotation.Nonnull;
32 | import javax.lang.model.element.Modifier;
33 |
34 | public class MapMethods {
35 |
36 | private static final TypeVariableName FOLD_RETURN_TYPE = TypeVariableName.get("R_");
37 | private final Iterable values;
38 |
39 | public MapMethods(Iterable values) {
40 | this.values = values;
41 | }
42 |
43 | private MethodSpec.Builder createFoldSignature(Iterable availableTypeVariables)
44 | throws ParserException {
45 | MethodSpec.Builder builder =
46 | MethodSpec.methodBuilder("map")
47 | .addTypeVariable(FOLD_RETURN_TYPE)
48 | .addModifiers(Modifier.PUBLIC)
49 | .returns(FOLD_RETURN_TYPE);
50 |
51 | for (OutputValue arg : values) {
52 | TypeName visitor =
53 | ParameterizedTypeName.get(
54 | ClassName.get(Function.class),
55 | TypeVariableUtils.withoutMissingTypeVariables(
56 | arg.parameterizedOutputClass(), availableTypeVariables),
57 | FOLD_RETURN_TYPE);
58 |
59 | builder.addParameter(
60 | ParameterSpec.builder(visitor, asCamelCase(arg.name()))
61 | .addAnnotation(Nonnull.class)
62 | .build());
63 | }
64 |
65 | return builder;
66 | }
67 |
68 | public MethodSpec createAbstractFoldMethod() throws ParserException {
69 | return createFoldSignature(null).addModifiers(Modifier.ABSTRACT).build();
70 | }
71 |
72 | public MethodSpec createFoldMethod(OutputValue value) throws ParserException {
73 | MethodSpec.Builder builder =
74 | createFoldSignature(value.typeVariables())
75 | .addAnnotation(Override.class)
76 | .addModifiers(Modifier.FINAL);
77 |
78 | builder.addStatement("return $L.apply(this)", asCamelCase(value.name()));
79 |
80 | return builder.build();
81 | }
82 |
83 | private static String asCamelCase(String text) {
84 | return Character.toLowerCase(text.charAt(0)) + text.substring(1);
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/dataenum-processor/src/main/java/com/spotify/dataenum/processor/generator/match/MatchMethods.java:
--------------------------------------------------------------------------------
1 | /*
2 | * -\-\-
3 | * DataEnum
4 | * --
5 | * Copyright (c) 2017 Spotify AB
6 | * --
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * -/-/-
19 | */
20 | package com.spotify.dataenum.processor.generator.match;
21 |
22 | import static com.spotify.dataenum.processor.generator.match.TypeVariableUtils.withoutMissingTypeVariables;
23 |
24 | import com.spotify.dataenum.function.Consumer;
25 | import com.spotify.dataenum.processor.data.OutputValue;
26 | import com.spotify.dataenum.processor.parser.ParserException;
27 | import com.squareup.javapoet.ClassName;
28 | import com.squareup.javapoet.MethodSpec;
29 | import com.squareup.javapoet.ParameterSpec;
30 | import com.squareup.javapoet.ParameterizedTypeName;
31 | import com.squareup.javapoet.TypeName;
32 | import com.squareup.javapoet.TypeVariableName;
33 | import javax.annotation.Nonnull;
34 | import javax.lang.model.element.Modifier;
35 |
36 | public class MatchMethods {
37 |
38 | private final Iterable values;
39 |
40 | public MatchMethods(Iterable values) {
41 | this.values = values;
42 | }
43 |
44 | private MethodSpec.Builder createFoldVoidSignature(
45 | Iterable availableTypeVariables) throws ParserException {
46 | MethodSpec.Builder builder =
47 | MethodSpec.methodBuilder("match").addModifiers(Modifier.PUBLIC).returns(void.class);
48 |
49 | for (OutputValue arg : values) {
50 | TypeName visitor =
51 | ParameterizedTypeName.get(
52 | ClassName.get(Consumer.class),
53 | withoutMissingTypeVariables(arg.parameterizedOutputClass(), availableTypeVariables));
54 |
55 | builder.addParameter(
56 | ParameterSpec.builder(visitor, asCamelCase(arg.name()))
57 | .addAnnotation(Nonnull.class)
58 | .build());
59 | }
60 |
61 | return builder;
62 | }
63 |
64 | public MethodSpec createAbstractFoldVoidMethod() throws ParserException {
65 | return createFoldVoidSignature(null).addModifiers(Modifier.ABSTRACT).build();
66 | }
67 |
68 | public MethodSpec createFoldVoidMethod(OutputValue value) throws ParserException {
69 | MethodSpec.Builder builder =
70 | createFoldVoidSignature(value.typeVariables())
71 | .addAnnotation(Override.class)
72 | .addModifiers(Modifier.FINAL);
73 |
74 | builder.addStatement("$L.accept(this)", asCamelCase(value.name()));
75 |
76 | return builder.build();
77 | }
78 |
79 | private static String asCamelCase(String text) {
80 | return Character.toLowerCase(text.charAt(0)) + text.substring(1);
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/dataenum-processor/src/main/java/com/spotify/dataenum/processor/generator/match/TypeVariableUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * -\-\-
3 | * DataEnum
4 | * --
5 | * Copyright (c) 2017 Spotify AB
6 | * --
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * -/-/-
19 | */
20 | package com.spotify.dataenum.processor.generator.match;
21 |
22 | import com.spotify.dataenum.processor.parser.ParserException;
23 | import com.spotify.dataenum.processor.util.Iterables;
24 | import com.squareup.javapoet.ParameterizedTypeName;
25 | import com.squareup.javapoet.TypeName;
26 | import com.squareup.javapoet.TypeVariableName;
27 | import java.util.ArrayList;
28 | import java.util.List;
29 |
30 | class TypeVariableUtils {
31 | static TypeName withoutMissingTypeVariables(
32 | TypeName typeName, Iterable availableTypeVariables) throws ParserException {
33 | if (!(typeName instanceof ParameterizedTypeName) || availableTypeVariables == null) {
34 | return typeName;
35 | }
36 |
37 | ParameterizedTypeName parameterizedTypeName = (ParameterizedTypeName) typeName;
38 |
39 | List adjustedArguments = new ArrayList<>();
40 | for (TypeName argument : parameterizedTypeName.typeArguments) {
41 | if (argument instanceof ParameterizedTypeName) {
42 | // Recursive call
43 | adjustedArguments.add(withoutMissingTypeVariables(argument, availableTypeVariables));
44 | } else if (argument instanceof TypeVariableName) {
45 | TypeVariableName variable = (TypeVariableName) argument;
46 | if (Iterables.contains(availableTypeVariables, variable)) {
47 | adjustedArguments.add(variable);
48 | } else {
49 | if (variable.bounds.size() == 0) {
50 | adjustedArguments.add(TypeName.OBJECT);
51 | } else if (variable.bounds.size() == 1) {
52 | adjustedArguments.add(variable.bounds.get(0));
53 | } else {
54 | throw new ParserException("More than one generic type bound is not supported");
55 | }
56 | }
57 | } else {
58 | adjustedArguments.add(argument);
59 | }
60 | }
61 |
62 | TypeName[] adjustedArgumentsArr = adjustedArguments.toArray(new TypeName[] {});
63 | return ParameterizedTypeName.get(parameterizedTypeName.rawType, adjustedArgumentsArr);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/dataenum-processor/src/main/java/com/spotify/dataenum/processor/generator/method/MethodMethods.java:
--------------------------------------------------------------------------------
1 | /*
2 | * -\-\-
3 | * DataEnum
4 | * --
5 | * Copyright (c) 2017 Spotify AB
6 | * --
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * -/-/-
19 | */
20 |
21 | package com.spotify.dataenum.processor.generator.method;
22 |
23 | import com.squareup.javapoet.*;
24 | import com.sun.source.tree.MethodTree;
25 | import com.sun.source.util.TreePathScanner;
26 | import com.sun.source.util.Trees;
27 | import java.util.concurrent.atomic.AtomicReference;
28 | import java.util.function.Consumer;
29 | import java.util.function.Function;
30 | import java.util.stream.Collectors;
31 | import java.util.stream.Stream;
32 | import javax.lang.model.element.AnnotationMirror;
33 | import javax.lang.model.element.ElementKind;
34 | import javax.lang.model.element.ExecutableElement;
35 | import javax.lang.model.element.Modifier;
36 |
37 | public final class MethodMethods {
38 | private MethodMethods() {}
39 |
40 | public static MethodSpec.Builder builderFrom(
41 | ExecutableElement el,
42 | Function, Stream> adjustModifiers,
43 | Function, Stream extends AnnotationMirror>>
44 | adjustAnnotations) {
45 | return MethodSpec.methodBuilder(el.getSimpleName().toString())
46 | .addModifiers(adjustModifiers.apply(el.getModifiers().stream()).collect(Collectors.toSet()))
47 | .addAnnotations(
48 | adjustAnnotations
49 | .apply(el.getAnnotationMirrors().stream())
50 | .map(AnnotationSpec::get)
51 | .collect(Collectors.toList()))
52 | .addTypeVariables(
53 | el.getTypeParameters().stream().map(TypeVariableName::get).collect(Collectors.toList()))
54 | .returns(TypeName.get(el.getReturnType()))
55 | .addParameters(
56 | el.getParameters().stream().map(ParameterSpec::get).collect(Collectors.toList()))
57 | .varargs(el.isVarArgs())
58 | .addExceptions(
59 | el.getThrownTypes().stream().map(TypeName::get).collect(Collectors.toList()));
60 | }
61 |
62 | public static CodeBlock codeBlockFrom(ExecutableElement el, Trees trees) {
63 | final MethodTree methodTree = MethodLookup.lookupTree(el, trees);
64 | return methodTree
65 | .getBody()
66 | .getStatements()
67 | .stream()
68 | .map(x -> CodeBlock.of(x.toString()))
69 | .reduce(CodeBlock.of(""), (a, b) -> a.toBuilder().add(b).build());
70 | }
71 |
72 | private static class MethodLookup extends TreePathScanner {
73 |
74 | private final Consumer onMethod;
75 |
76 | private MethodLookup(Consumer onMethod) {
77 | this.onMethod = onMethod;
78 | }
79 |
80 | public static MethodTree lookupTree(ExecutableElement methodElement, Trees trees) {
81 | assert methodElement.getKind() == ElementKind.METHOD;
82 |
83 | AtomicReference methodRef = new AtomicReference<>();
84 | new MethodLookup(methodRef::set).scan(trees.getPath(methodElement), null);
85 | MethodTree method = methodRef.get();
86 | assert method != null;
87 |
88 | return method;
89 | }
90 |
91 | @Override
92 | public Void visitMethod(MethodTree methodTree, Void v) {
93 | this.onMethod.accept(methodTree);
94 | return super.visitMethod(methodTree, v);
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/dataenum-processor/src/main/java/com/spotify/dataenum/processor/generator/spec/SpecTypeFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * -\-\-
3 | * DataEnum
4 | * --
5 | * Copyright (c) 2017 Spotify AB
6 | * --
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * -/-/-
19 | */
20 | package com.spotify.dataenum.processor.generator.spec;
21 |
22 | import static com.spotify.dataenum.processor.util.Iterables.fromOptional;
23 |
24 | import com.spotify.dataenum.processor.DataEnumProcessor;
25 | import com.spotify.dataenum.processor.data.OutputSpec;
26 | import com.spotify.dataenum.processor.data.OutputValue;
27 | import com.spotify.dataenum.processor.generator.match.MapMethods;
28 | import com.spotify.dataenum.processor.generator.match.MatchMethods;
29 | import com.spotify.dataenum.processor.generator.value.ValueMethods;
30 | import com.spotify.dataenum.processor.generator.value.ValueTypeFactory;
31 | import com.spotify.dataenum.processor.parser.ParserException;
32 | import com.spotify.dataenum.processor.util.Iterables;
33 | import com.squareup.javapoet.AnnotationSpec;
34 | import com.squareup.javapoet.CodeBlock;
35 | import com.squareup.javapoet.MethodSpec;
36 | import com.squareup.javapoet.TypeSpec;
37 | import java.util.ArrayList;
38 | import java.util.List;
39 | import java.util.Optional;
40 | import javax.annotation.Generated;
41 | import javax.lang.model.element.Element;
42 | import javax.lang.model.element.Modifier;
43 |
44 | public final class SpecTypeFactory {
45 |
46 | private SpecTypeFactory() {}
47 |
48 | public static TypeSpec create(
49 | OutputSpec spec, Optional constructorAccessModifier, Element element)
50 | throws ParserException {
51 | List valueTypes = new ArrayList<>();
52 | List factoryMethods = new ArrayList<>();
53 | List isMethods = new ArrayList<>();
54 | List asMethods = new ArrayList<>();
55 |
56 | MatchMethods matchMethods = new MatchMethods(spec.outputValues());
57 | MapMethods mapMethods = new MapMethods(spec.outputValues());
58 |
59 | for (OutputValue value : spec.outputValues()) {
60 | valueTypes.add(
61 | ValueTypeFactory.create(
62 | value, spec, matchMethods, mapMethods, constructorAccessModifier));
63 |
64 | ValueMethods valueMethods = new ValueMethods(value);
65 | factoryMethods.add(valueMethods.createFactoryMethod(spec));
66 | isMethods.add(valueMethods.createIsMethod());
67 | asMethods.add(valueMethods.createAsMethod(spec));
68 | }
69 |
70 | TypeSpec.Builder enumBuilder =
71 | TypeSpec.classBuilder(spec.outputClass())
72 | .addOriginatingElement(element)
73 | .addJavadoc("Generated from {@link $T}\n", spec.specClass())
74 | .addAnnotation(
75 | AnnotationSpec.builder(Generated.class)
76 | .addMember(
77 | "value", CodeBlock.of("$S", DataEnumProcessor.class.getCanonicalName()))
78 | .build())
79 | .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
80 | .addTypeVariables(spec.typeVariables())
81 | .addSuperinterfaces(spec.superInterfaces());
82 |
83 | // add constructor with correct access
84 | enumBuilder.addMethod(
85 | MethodSpec.constructorBuilder()
86 | .addModifiers(fromOptional(constructorAccessModifier))
87 | .build());
88 |
89 | enumBuilder.addTypes(valueTypes);
90 | enumBuilder.addMethods(factoryMethods);
91 | enumBuilder.addMethods(isMethods);
92 | enumBuilder.addMethods(asMethods);
93 |
94 | if (!Iterables.isEmpty(spec.outputValues())) {
95 | enumBuilder.addMethod(matchMethods.createAbstractFoldVoidMethod());
96 | enumBuilder.addMethod(mapMethods.createAbstractFoldMethod());
97 | }
98 |
99 | enumBuilder.addMethods(spec.methods());
100 |
101 | return enumBuilder.build();
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/dataenum-processor/src/main/java/com/spotify/dataenum/processor/generator/value/ValueMethods.java:
--------------------------------------------------------------------------------
1 | /*
2 | * -\-\-
3 | * DataEnum
4 | * --
5 | * Copyright (c) 2017 Spotify AB
6 | * --
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * -/-/-
19 | */
20 | package com.spotify.dataenum.processor.generator.value;
21 |
22 | import com.spotify.dataenum.processor.data.OutputSpec;
23 | import com.spotify.dataenum.processor.data.OutputValue;
24 | import com.spotify.dataenum.processor.data.Parameter;
25 | import com.squareup.javapoet.AnnotationSpec;
26 | import com.squareup.javapoet.MethodSpec;
27 | import com.squareup.javapoet.MethodSpec.Builder;
28 | import com.squareup.javapoet.ParameterSpec;
29 | import java.util.ArrayList;
30 | import java.util.List;
31 | import javax.annotation.Nonnull;
32 | import javax.annotation.Nullable;
33 | import javax.lang.model.element.Modifier;
34 |
35 | public class ValueMethods {
36 |
37 | private final OutputValue value;
38 |
39 | public ValueMethods(OutputValue value) {
40 | this.value = value;
41 | }
42 |
43 | public MethodSpec createFactoryMethod(OutputSpec spec) {
44 | MethodSpec.Builder factory =
45 | MethodSpec.methodBuilder(asCamelCase(value.name()))
46 | .addTypeVariables(spec.typeVariables())
47 | .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
48 | .returns(spec.parameterizedOutputClass());
49 |
50 | if (value.javadoc() != null) {
51 | factory.addJavadoc(value.javadoc() + "\n\n");
52 | }
53 |
54 | factory.addJavadoc(
55 | "@return a {@link $T} (see {@link $T#$L} for source)\n",
56 | value.outputClass(),
57 | spec.specClass(),
58 | value.name());
59 |
60 | for (AnnotationSpec annotationSpec : value.annotations()) {
61 | factory.addAnnotation(annotationSpec);
62 | }
63 |
64 | StringBuilder newString = new StringBuilder();
65 | List