Skip to content

Commit ddd8c55

Browse files
authored
92 basic date time types (#94)
* Parse and emit date/time type * Fix ConstantTypeDefParser to skip not explicitly annotated type * Config date time type target type literal * Simplify and add test for Context, now super type check is based on String, due to TypeMirror cannot be acquired by name for a dependency class * Update javadoc on SharedType
1 parent b90b294 commit ddd8c55

45 files changed

Lines changed: 449 additions & 134 deletions

Some content is hidden

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

annotation/src/main/java/online/sharedtype/SharedType.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
* <p>
5050
* <b>Cyclic Reference:</b>
5151
* <ul>
52+
* <li>Typescript: Cyclic referenced field will be optional.</li>
5253
* <li>Rust: Cyclic references will be wrapped in {@code Option<Box<T>>}.</li>
5354
* </ul>
5455
*
@@ -83,14 +84,22 @@
8384
* </ul>
8485
*
8586
* <p>
86-
* <b>Maps:</b>
87+
* <b>Maps:</b><br>
8788
* Key must be String or numeric types. Enum is support given that its value is a literal.
8889
* Custom map types are supported, e.g. a class that extends HashMap. But the type itself is treated as a mapType, so its structure will not be emitted.
8990
* <ul>
9091
* <li>Typescript: e.g. {@code Record<string, T>} where {@code T} can be a reified type. If the key is enum, it will be a {@code Partial<Record<?, ?>>}</li>
9192
* <li>Rust: e.g. {@code HashMap<String, T>}, {@code HashMap<EnumType, T>}</li>
9293
* </ul>
9394
*
95+
* <p>
96+
* <b>Date and Time:</b><br>
97+
* By default, types that are recognized as date and time are emitted as strings, date/time types are configured via global properties.
98+
* The emitted target type can be configured via global properties or via this annotation.
99+
* Target type can be any type literal, but SharedType will not verify its validity in emitted code.
100+
* </p>
101+
*
102+
* <br>
94103
* <p><a href="https://github.com/SharedType/sharedtype">SharedType Website</a></p>
95104
*
96105
* @author Cause Chung
@@ -152,6 +161,12 @@
152161
*/
153162
String[] rustMacroTraits() default {};
154163

164+
/**
165+
* Type literal to be emitted for date/time types. How a java type is considered a date/time type is defined by global properties.
166+
* @return any literal, e.g. "String", "chrono::DateTime". When empty, fallback to global default.
167+
*/
168+
String rustTargetDatetimeTypeLiteral() default "";
169+
155170
/**
156171
* How to render optional fields in Typescript.
157172
* @return combination of "?", "null", "undefined", the latter 2 are rendered as union types. If empty, fallback to global default.
@@ -173,6 +188,12 @@
173188
*/
174189
String typescriptFieldReadonlyType() default "";
175190

191+
/**
192+
* Type literal to be emitted for date/time types. How a java type is considered a date/time type is defined by global properties.
193+
* @return any literal, e.g. "string", "Date". When empty, fallback to global default.
194+
*/
195+
String typescriptTargetDatetimeTypeLiteral() default "";
196+
176197
/**
177198
* Mark a method as an accessor regardless of its name.
178199
* Getter prefixes are configured in global properties.

client-test/typescript/src/types.java17.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import {
33
EnumTShirt, type JavaRecord, type AnotherJavaClass, type RecursiveClass, type MapClass,
44
type OptionalMethod,
55
type ArrayClass,
6+
type JavaTimeClass,
7+
type JodaTimeClass,
68
} from "./index.java17";
79

810
export const list1: EnumGalaxy[] = ["Andromeda", "MilkyWay", "Triangulum"];
@@ -106,3 +108,24 @@ optionalMethods.nestedValueOptional = "bar";
106108
export const arrayClass: ArrayClass = {
107109
arr: ["abc"],
108110
}
111+
112+
export const javaTime: JavaTimeClass = {
113+
utilDate: new Date(),
114+
sqlDate: new Date(),
115+
localDate: new Date(),
116+
localTime: new Date(),
117+
localDateTime: new Date(),
118+
zonedDateTime: new Date(),
119+
offsetDateTime: new Date(),
120+
offsetTime: new Date(),
121+
instant: new Date(),
122+
}
123+
124+
export const jodaTime: JodaTimeClass = {
125+
jodaDateTime: "2022-01-01T00:00:00.000+08:00",
126+
jodaLocalDate: "2022-01-01T00:00:00.000+08:00",
127+
jodaMonthDay: "2022-01-01T00:00:00.000+08:00",
128+
jodaLocalTime: "2022-01-01T00:00:00.000+08:00",
129+
jodaLocalDateTime: "2022-01-01T00:00:00.000+08:00",
130+
jodaOffsetDateTime: "2022-01-01T00:00:00.000+08:00",
131+
}

internal/src/main/java/online/sharedtype/processor/domain/ArrayTypeInfo.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
* Represents an array-like type.
1010
* During parsing, a predefined array-like type and its subtypes is captured as this class.
1111
* A type will be recognized as this type with higher priority than {@link ConcreteTypeInfo}.
12+
* It has no counterpart typeDef, explicitly annotating {@code @SharedType} on an array type is ignored with a warning.
1213
* <br>
1314
* Predefined array-like types can be configured in global properties. Default is {@link java.lang.Iterable}.
1415
*

internal/src/main/java/online/sharedtype/processor/domain/ClassDef.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,7 @@ public Set<ConcreteTypeInfo> typeInfoSet() {
6969
}
7070

7171
public boolean isMapType() {
72-
return typeInfoSet.stream().anyMatch(ConcreteTypeInfo::isMapType);
73-
}
74-
public boolean isArrayType() {
75-
return typeInfoSet.stream().anyMatch(ConcreteTypeInfo::isArrayType);
72+
return typeInfoSet.stream().anyMatch(t -> t.getKind() == ConcreteTypeInfo.Kind.MAP);
7673
}
7774

7875
public void addSubtype(TypeDef subtype) {

internal/src/main/java/online/sharedtype/processor/domain/ConcreteTypeDef.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
public abstract class ConcreteTypeDef implements TypeDef {
1313
private static final long serialVersionUID = 2346502341189835693L;
1414
/** Whether this type is explicitly annotated with {@link online.sharedtype.SharedType} */
15-
private boolean annotated;
15+
private final boolean annotated;
1616
/** Directly or indirectly referenced by a type that is annotated. */
1717
private boolean referencedByAnnotated;
1818

internal/src/main/java/online/sharedtype/processor/domain/ConcreteTypeInfo.java

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,17 @@
1313
import java.util.stream.Collectors;
1414

1515
/**
16-
* Represents a primitive type or object type that requires its target representation,
17-
* and is not recognized as an array-like type.
16+
* <p>
17+
* Represents a general primitive type or object type that requires its target representation.
1818
* Like {@link java.lang.String} in typescript as "string", int in typescript as "number".
19+
* </p>
20+
* <p>
21+
* Type with typical signature and render pattern like array-like types are represented as other type info.
22+
* </p>
1923
*
20-
* @see ArrayTypeInfo
2124
* @author Cause Chung
25+
* @see ArrayTypeInfo
26+
* @see Kind
2227
*/
2328
@EqualsAndHashCode(of = {"qualifiedName", "typeArgs"})
2429
@Builder(toBuilder = true)
@@ -29,19 +34,12 @@ public final class ConcreteTypeInfo implements TypeInfo {
2934
@Builder.Default
3035
private final List<TypeInfo> typeArgs = Collections.emptyList();
3136

32-
/** If this type is an Enum */
33-
@Getter
34-
private final boolean enumType;
35-
36-
/** If this type is map-like. */
37-
@Getter
38-
private final boolean mapType;
39-
40-
/** If this type is array-like. */
4137
@Getter
42-
private final boolean arrayType;
38+
private final Kind kind;
4339

44-
/** If this type is defined in global config as base Map type */
40+
/**
41+
* If this type is defined in global config as base Map type
42+
*/
4543
@Getter
4644
private final boolean baseMapType;
4745

@@ -55,6 +53,7 @@ public final class ConcreteTypeInfo implements TypeInfo {
5553

5654
/**
5755
* The counter-parting type definition.
56+
*
5857
* @see #typeDef()
5958
*/
6059
@Nullable
@@ -117,8 +116,17 @@ public List<TypeInfo> typeArgs() {
117116
public String toString() {
118117
return String.format("%s%s%s",
119118
qualifiedName,
120-
typeArgs.isEmpty() ? "" : "<" + typeArgs.stream().map(TypeInfo::toString).collect(Collectors.joining(",")) + ">",
121-
resolved ? "" : "?"
119+
typeArgs.isEmpty() ? "" : "<" + typeArgs.stream().map(TypeInfo::toString).collect(Collectors.joining(",")) + ">",
120+
resolved ? "" : "?"
122121
);
123122
}
123+
124+
/**
125+
* Kind of types ConcreteTypeInfo can represent.
126+
* Array is represented by ArrayTypeInfo.
127+
* Date/Time is represented by DateTimeTypeInfo.
128+
*/
129+
public enum Kind {
130+
ENUM, MAP, OTHER
131+
}
124132
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package online.sharedtype.processor.domain;
2+
3+
import lombok.RequiredArgsConstructor;
4+
5+
/**
6+
* Represents a date/time type, which is simply be emitted as a string or any custom type literal.
7+
* It has no counterpart typeDef, explicitly annotating {@code @SharedType} on a date/time type is ignored with a warning.
8+
*
9+
* @author Cause Chung
10+
*/
11+
@RequiredArgsConstructor
12+
public final class DateTimeInfo implements TypeInfo {
13+
private static final long serialVersionUID = 5428192893749821359L;
14+
15+
private final String qualifiedName;
16+
17+
public String qualifiedName() {
18+
return qualifiedName;
19+
}
20+
21+
@Override
22+
public String toString() {
23+
return String.format("DateTime(%s)", qualifiedName);
24+
}
25+
}

internal/src/main/java/online/sharedtype/processor/domain/TypeDef.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ default List<TypeInfo> directSupertypes() {
3232
void setCyclicReferenced(boolean cyclicReferenced);
3333

3434
boolean isAnnotated();
35-
void setAnnotated(boolean annotated);
3635

3736
boolean isReferencedByAnnotated();
3837
void setReferencedByAnnotated(boolean referencedByAnnotated);

internal/src/main/java/online/sharedtype/processor/domain/TypeInfo.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,8 @@ public interface TypeInfo extends Serializable {
2323
*
2424
* @return true is this type and its dependency types are resolved.
2525
*/
26-
boolean resolved();
27-
28-
default boolean isEnumType() {
29-
return false;
26+
default boolean resolved() {
27+
return true;
3028
}
3129

3230
/**
@@ -35,5 +33,7 @@ default boolean isEnumType() {
3533
* value is a type argument, a concrete type e.g. Integer, or a generic type with concrete type parameter, e.g. {@code Tuple<String, String>}
3634
* @return a newly created type info if updated.
3735
*/
38-
TypeInfo reify(Map<TypeVariableInfo, TypeInfo> mappings);
36+
default TypeInfo reify(Map<TypeVariableInfo, TypeInfo> mappings) {
37+
return this;
38+
}
3939
}

internal/src/main/java/online/sharedtype/processor/domain/TypeVariableInfo.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,6 @@ public String qualifiedName() {
4343
return qualifiedName;
4444
}
4545

46-
@Override
47-
public boolean resolved() {
48-
return true;
49-
}
50-
5146
@Override
5247
public TypeInfo reify(Map<TypeVariableInfo, TypeInfo> mappings) {
5348
TypeInfo reifiedType = mappings.get(this);

0 commit comments

Comments
 (0)