Skip to content

Commit 35fb83e

Browse files
authored
1 logging and exception review (#46)
* Refine ap logging * Refine exception and messages
1 parent f5e6bff commit 35fb83e

File tree

7 files changed

+73
-44
lines changed

7 files changed

+73
-44
lines changed

README.md

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,53 @@
11
[![CI](https://github.com/cuzfrog/sharedtype/actions/workflows/ci.yaml/badge.svg)](https://github.com/cuzfrog/sharedtype/actions/workflows/ci.yaml)
22
# SharedType - Sharing Java Types made easy
3+
From Java:
4+
```java
5+
@SharedType
6+
record User(String name, int age, String email) {}
7+
```
8+
To Typescript:
9+
```typescript
10+
export interface User {
11+
name: string;
12+
age: number;
13+
email: string;
14+
}
15+
```
16+
Go (Planed):
17+
```golang
18+
type User struct {
19+
Name string
20+
Age int
21+
Email string
22+
}
23+
```
24+
Rust (Planed):
25+
```rust
26+
struct User {
27+
name: String,
28+
age: i32,
29+
email: String,
30+
}
31+
```
32+
And more.
333

4-
* Client Java version >= 8.
5-
* Only client source dependency is `@SharedType`.
6-
* SharedType annotation processor jar is <100KB, only 2 small dependencies: jsr305 annotations and mustache.
7-
* Parsing takes milliseconds. See [Performance](doc/Performance.md).
8-
* Put `@SharedType` and there you go.
9-
* Global + class level options.
10-
* (Not Implemented) Compile time resolvable values. E.g. constant literals.
11-
* Generics and complex type structures.
12-
* (Only TS Implemented) Multiple target schemas, extendable.
34+
## Features
35+
* Java8 full support. No hassles.
36+
* Client source dependency is only `@SharedType`. Nothing gets into bytecode/runtime.
37+
* SharedType AP jars <100KB, only 2 small dependencies: jsr305 annotations and mustache. Download less.
38+
* Parsing takes milliseconds with `-proc:only`. Implemented with performance in head.
39+
* Intuitive defaults, put `@SharedType` and there you go.
40+
* Global + class level options. Fine tune your configs.
41+
* Generics support.
42+
* (Planed) Constant support.
1343

14-
## Alternatives
44+
## Similar Projects
1545
* [bsorrentino/java2typescript](https://github.com/bsorrentino/java2typescript)
1646
* [vojtechhabarta/typescript-generator](https://github.com/vojtechhabarta/typescript-generator)
1747

1848
## Documentation
1949
* [User Guide](doc/Usage.md)
20-
* [Development Guide](doc/Development.md)
50+
* [Developer Guide](doc/Development.md)
2151

2252
## Authors
2353
Cause Chung ([email protected])

doc/Usage.md

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,7 @@ Setup annotation processing:
4646
Annotate on a class:
4747
```java
4848
@SharedType
49-
record User(
50-
String name,
51-
int age,
52-
String email
53-
) {
54-
}
49+
record User(String name, int age, String email) {}
5550
```
5651

5752
Execute annotation processing:

processor/src/main/java/org/sharedtype/processor/AnnotationProcessorImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
6666
return ANNOTATION_CONSUMED;
6767
}
6868
if (annotations.size() > 1) {
69-
throw new SharedTypeInternalError(String.format("Only '%s' is expected.", ANNOTATION_QUALIFIED_NAME));
69+
throw new SharedTypeInternalError(String.format("Only annotation %s is expected.", ANNOTATION_QUALIFIED_NAME));
7070
}
7171
TypeElement annotation = annotations.iterator().next();
7272
checkArgument(annotation.getQualifiedName().contentEquals(ANNOTATION_QUALIFIED_NAME), "Wrong anno: %s", annotation);
@@ -88,7 +88,7 @@ void doProcess(Set<? extends Element> elements) {
8888
ctx.warning("Type '%s' is ignored or invalid, but annotated with '%s'.", typeElement.getQualifiedName().toString(), ANNOTATION_QUALIFIED_NAME);
8989
}
9090
} else {
91-
throw new UnsupportedOperationException("Unsupported element: " + element);
91+
throw new SharedTypeInternalError(String.format("Unsupported element: %s of kind %s", element, element.getKind()));
9292
}
9393
}
9494
List<TypeDef> resolvedDefs = resolver.resolve(discoveredDefs);

processor/src/main/java/org/sharedtype/processor/parser/ClassTypeDefParser.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public TypeDef parse(TypeElement typeElement) {
6565

6666
private boolean isValidClassTypeElement(TypeElement typeElement) {
6767
if (typeElement.getNestingKind() != NestingKind.TOP_LEVEL && !typeElement.getModifiers().contains(Modifier.STATIC)) {
68-
ctx.error("Class %s is not static." +
68+
ctx.error("Class %s is not static, non-static inner class is not supported." +
6969
" Instance class may refer to its enclosing class's generic type without the type declaration on its own," +
7070
" which could break the generated code. Later version of SharedType may loosen this limitation.", typeElement);
7171
return false;
@@ -151,7 +151,7 @@ List<Tuple<Element, String>> resolveComponents(TypeElement typeElement, Config c
151151
boolean explicitAccessor = methodElem.getAnnotation(SharedType.Accessor.class) != null;
152152
if (!isZeroArgNonstaticMethod(methodElem)) {
153153
if (explicitAccessor) {
154-
ctx.warning("Method '%s' annotated with @SharedType.Accessor is not a zero-arg nonstatic method.", methodElem);
154+
ctx.warning("%s.%s annotated with @SharedType.Accessor is not a zero-arg nonstatic method.", typeElement, methodElem);
155155
}
156156
continue;
157157
}
@@ -170,7 +170,8 @@ List<Tuple<Element, String>> resolveComponents(TypeElement typeElement, Config c
170170
// TODO: CONSTANTS
171171

172172
if (uniqueNamesOfTypes.ignoredType != null) {
173-
ctx.error("%s.%s references to explicitly ignored type %s.",typeElement, name, uniqueNamesOfTypes.ignoredType);
173+
ctx.error("%s.%s references to explicitly ignored type %s, which is not allowed." +
174+
" Either remove the ignored type, or add @SharedType.Ignore to the field or accessor.",typeElement, name, uniqueNamesOfTypes.ignoredType);
174175
return Collections.emptyList();
175176
}
176177
}
@@ -217,7 +218,8 @@ boolean contains(String name, TypeMirror componentType) {
217218
return false;
218219
}
219220
if (!types.isSameType(type, componentType)) {
220-
ctx.error("Type %s has components with same name '%s' that have different types '%s' and '%s'", contextType, name, type, componentType);
221+
ctx.error("Type %s has conflicting components with same name '%s', because they have different types %s and %s, they cannot be merged.",
222+
contextType, name, type, componentType);
221223
}
222224
return true;
223225
}

processor/src/main/java/org/sharedtype/processor/parser/EnumTypeDefParser.java

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public TypeDef parse(TypeElement typeElement) {
5858
.qualifiedName(config.getQualifiedName())
5959
.simpleName(config.getName())
6060
.enumValueInfos(
61-
enumValueMarker.marked() ? parseEnumConstants(enumConstantElems, enumValueMarker) : useEnumConstantNames(enumConstantElems)
61+
enumValueMarker.marked() ? parseEnumConstants(typeElement, enumConstantElems, enumValueMarker) : useEnumConstantNames(enumConstantElems)
6262
)
6363
.build();
6464
}
@@ -71,7 +71,7 @@ private static List<EnumValueInfo> useEnumConstantNames(List<VariableElement> en
7171
return res;
7272
}
7373

74-
private List<EnumValueInfo> parseEnumConstants(List<VariableElement> enumConstants, EnumValueMarker enumValueMarker) {
74+
private List<EnumValueInfo> parseEnumConstants(TypeElement enumTypeElement, List<VariableElement> enumConstants, EnumValueMarker enumValueMarker) {
7575
List<EnumValueInfo> res = new ArrayList<>(enumConstants.size());
7676
TypeInfo valueTypeInfo = typeInfoParser.parse(enumValueMarker.enumValueVariableElem.asType());
7777
int ctorArgIdx = enumValueMarker.matchAndGetConstructorArgIdx();
@@ -82,22 +82,24 @@ private List<EnumValueInfo> parseEnumConstants(List<VariableElement> enumConstan
8282
Tree tree = ctx.getTrees().getTree(enumConstant);
8383
if (tree instanceof VariableTree) {
8484
VariableTree variableTree = (VariableTree) tree;
85-
Object value = resolveValue(variableTree, ctorArgIdx);
85+
Object value = resolveValue(enumTypeElement, variableTree, ctorArgIdx);
8686
if (value != null) {
8787
res.add(new EnumValueInfo(valueTypeInfo, value));
8888
}
8989
} else if (tree == null) {
90-
ctx.error("Literal value cannot be parsed from enum constant: %s, because source tree from the element is null." +
90+
ctx.error("Literal value cannot be parsed from enum constant: %s of enum %s, because source tree from the element is null." +
9191
" This could mean at the time of the annotation processing, the source tree was not available." +
92-
" Is this class from a dependency jar/compiled class file? Please refer to the documentation for more information.", enumConstant);
92+
" Is this class from a dependency jar/compiled class file? Please refer to the documentation for more information.",
93+
enumConstant, enumTypeElement);
9394
} else {
94-
throw new SharedTypeInternalError(String.format("Unsupported tree, kind: %s, tree: %s, element: %s", tree.getKind(), tree, enumConstant));
95+
throw new SharedTypeInternalError(String.format(
96+
"Unsupported tree during parsing enum %s, kind: %s, tree: %s, element: %s", enumTypeElement, tree.getKind(), tree, enumConstant));
9597
}
9698
}
9799
return res;
98100
}
99101

100-
private Object resolveValue(VariableTree tree, int ctorArgIdx) {
102+
private Object resolveValue(TypeElement enumTypeElement, VariableTree tree, int ctorArgIdx) {
101103
ExpressionTree init = tree.getInitializer();
102104
if (init instanceof NewClassTree) {
103105
NewClassTree newClassTree = (NewClassTree) init;
@@ -107,16 +109,16 @@ private Object resolveValue(VariableTree tree, int ctorArgIdx) {
107109
LiteralTree argLiteralTree = (LiteralTree) argTree;
108110
return argLiteralTree.getValue();
109111
} else {
110-
ctx.error("Unsupported argument: %s in %s, argIndex: %s. Only literals are supported as enum value."
111-
, argTree, tree, ctorArgIdx);
112+
ctx.error("Unsupported argument in enum type %s: %s in %s, argIndex: %s. Only literals are supported as enum value.",
113+
enumTypeElement, argTree, tree, ctorArgIdx);
112114
return null;
113115
}
114116
} catch (IndexOutOfBoundsException e) {
115117
throw new SharedTypeInternalError(String.format(
116-
"Initializer has incorrect number of arguments: %s in tree: %s, argIndex: %s", init, tree, ctorArgIdx));
118+
"Initializer in enum %s has incorrect number of arguments: %s in tree: %s, argIndex: %s", enumTypeElement, init, tree, ctorArgIdx));
117119
}
118120
}
119-
throw new SharedTypeInternalError(String.format("Unsupported initializer: %s in tree: %s", init, tree));
121+
throw new SharedTypeInternalError(String.format("Unsupported initializer in enum %s: %s in tree: %s", enumTypeElement, init, tree));
120122
}
121123

122124
@RequiredArgsConstructor
@@ -142,7 +144,7 @@ void parseConstructor(ExecutableElement constructor) {
142144

143145
void setField(VariableElement enumValueVariableElem) {
144146
if (this.enumValueVariableElem != null) {
145-
ctx.error("Enum '%s' has multiple annotation @%s usage, only one field or constructor parameter is allowed, found on %s and %s",
147+
ctx.error("Enum %s has multiple annotation @%s usage, only one field or constructor parameter is allowed, found on %s and %s",
146148
config.getQualifiedName(), SharedType.EnumValue.class, this.enumValueVariableElem, enumValueVariableElem);
147149
} else {
148150
this.enumValueVariableElem = enumValueVariableElem;
@@ -166,12 +168,13 @@ int matchAndGetConstructorArgIdx() {
166168
String lombokSuggestion = "";
167169
if (constructorArgNames.isEmpty()) {
168170
lombokSuggestion = "The discovered constructor has 0 parameter, if Lombok is used to generate the constructor," +
169-
" please ensure annotation processing of Lombok is executed before SharedType.";
171+
" please ensure annotation processing of Lombok is executed before SharedType. Or add explicit constructor." +
172+
" Later version of SharedType may infer constructor parameter position by field position without an explicit constructor.";
170173
}
171174

172-
ctx.error("Enum '%s' has @%s annotated on a field, but no constructor parameter can be matched."
175+
ctx.error("Enum %s has @%s annotated on a field, but no constructor parameter can be matched."
173176
+ lombokSuggestion
174-
+ " Please refer to the documentation on how to correctly use mark enum value.",
177+
+ " May refer to the documentation on how to correctly mark enum value.",
175178
config.getQualifiedName(), SharedType.EnumValue.class);
176179
return -1;
177180
}

processor/src/main/java/org/sharedtype/processor/parser/type/TypeInfoParserImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public TypeInfo parse(TypeMirror typeMirror) {
4646
} else if (typeKind == TypeKind.EXECUTABLE) {
4747
return parse(((ExecutableType) typeMirror).getReturnType());
4848
}
49-
throw new SharedTypeInternalError(String.format("Unsupported field type, element: %s, typeKind: %s", typeMirror, typeKind)); // TODO: context info
49+
throw new SharedTypeInternalError(String.format("Unsupported type: %s, typeKind: %s", typeMirror, typeKind));
5050
}
5151

5252
private TypeInfo parseDeclared(DeclaredType declaredType) {

processor/src/main/java/org/sharedtype/processor/resolver/LoopTypeResolver.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public List<TypeDef> resolve(List<TypeDef> typeDefs) {
7878
}
7979
}
8080
} else {
81-
throw new SharedTypeInternalError("Unsupported type: " + typeDef.getClass());
81+
throw new SharedTypeInternalError("Unsupported TypeDef type: " + typeDef.getClass());
8282
}
8383

8484
resolveTypeInfo(processingDefStack, processingInfoStack);
@@ -113,11 +113,10 @@ private void resolveTypeInfo(Deque<TypeDef> processingDefStack, Deque<TypeInfo>
113113
}
114114
} else if (typeInfo instanceof TypeVariableInfo) {
115115
TypeVariableInfo typeVariableInfo = (TypeVariableInfo) typeInfo;
116-
throw new UnsupportedOperationException("Type variable not supported yet: " + typeVariableInfo);
116+
throw new SharedTypeInternalError("TypeVariableInfo is not supported yet: " + typeVariableInfo);
117117
} else {
118-
throw new SharedTypeInternalError(
119-
String.format("Only ConcreteTypeInfo needs to be resolved, but got typeInfo: %s with %s", typeInfo, typeInfo.getClass())
120-
);
118+
throw new SharedTypeInternalError(String.format(
119+
"Only ConcreteTypeInfo needs to be resolved, but got: %s of %s", typeInfo, typeInfo.getClass()));
121120
}
122121
}
123122
}

0 commit comments

Comments
 (0)