Skip to content

Commit cf01e5e

Browse files
authored
Merge pull request #77 from atsu85/issue-76-javaType-to-TS-Declare-Type
feat(typeMapping): fix #76 - allow adding type mapping from java clas…
2 parents 84942e5 + e08b207 commit cf01e5e

File tree

6 files changed

+119
-2
lines changed

6 files changed

+119
-2
lines changed

java2typescript-jackson/README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,23 @@ new Configuration().addType(CustomDate.class, DateType.getInstance())
131131

132132
where `DateType` class specifies the expected output type name.
133133

134+
135+
##### Emitting `declare type SomeTypeName = SomeOtherTypeOrTypeExpression` instead of interface
136+
There are cases where instead of asking to emit TypeScript interface for specific Java type,
137+
You might want to specify the TypeScript type declaration
138+
(with potentially different type name)
139+
to be used instead of the interface of the Java type. Here is an example:
140+
141+
You might have `LocalDate` class in Java, and custom deserializer that can accept either string or number, so that in TypeScript You should be able to assign either of them to that type:
142+
```TypeScript
143+
type DateWithoutTime = string | number;
144+
```
145+
This could be accomplished using custom configuration:
146+
```Java
147+
Configuration conf = new Configuration()
148+
.addType(LocalDate.class, new TypeDeclarationType("DateWithoutTime", "string | number"));
149+
```
150+
There are more use-cases for this solution - see
151+
[the description of the issue](https://github.com/raphaeljolivet/java2typescript/issues/76)
152+
and the test [source](src/test/java/java2typescript/jackson/module/CustomTypeDefinitionGeneratorTest.java#L82)
153+
and [output](src/test/resources/java2typescript/jackson/module/CustomTypeDefinitionGeneratorTest.classWithCustomTypeFields.d.ts) as an example.

java2typescript-jackson/src/main/java/java2typescript/jackson/module/DefinitionGenerator.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,16 @@
1616
package java2typescript.jackson.module;
1717

1818
import java.util.Collection;
19-
import java2typescript.jackson.module.grammar.Module;
20-
import java2typescript.jackson.module.visitors.TSJsonFormatVisitorWrapper;
2119

20+
import com.fasterxml.jackson.databind.JavaType;
2221
import com.fasterxml.jackson.databind.JsonMappingException;
2322
import com.fasterxml.jackson.databind.ObjectMapper;
23+
import com.fasterxml.jackson.databind.type.SimpleType;
24+
25+
import java2typescript.jackson.module.grammar.Module;
26+
import java2typescript.jackson.module.grammar.TypeDeclarationType;
27+
import java2typescript.jackson.module.grammar.base.AbstractType;
28+
import java2typescript.jackson.module.visitors.TSJsonFormatVisitorWrapper;
2429

2530
/**
2631
* Main class that generates a TypeScript grammar tree (a Module), out of a
@@ -51,6 +56,15 @@ public Module generateTypeScript(String moduleName, Collection<? extends Class<?
5156
TSJsonFormatVisitorWrapper visitor = new TSJsonFormatVisitorWrapper(module, conf);
5257

5358
for (Class<?> clazz : classes) {
59+
AbstractType customType = conf.getCustomTypes().get(clazz.getName());
60+
if(customType != null && customType instanceof TypeDeclarationType) {
61+
// When the class is registered as TypeDeclarationType, then ...
62+
String tsTypeName = conf.getNamingStrategy().getName(SimpleType.construct(clazz));
63+
// ... add that type to the module ...
64+
module.getNamedTypes().put(tsTypeName, (TypeDeclarationType)customType);
65+
// ... instead of inspecting class body
66+
continue;
67+
}
5468
mapper.acceptJsonFormatVisitor(clazz, visitor);
5569
}
5670
return module;
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package java2typescript.jackson.module.grammar;
2+
3+
import static java.lang.String.format;
4+
5+
import java.io.IOException;
6+
import java.io.Writer;
7+
8+
import java2typescript.jackson.module.grammar.base.AbstractNamedType;
9+
import java2typescript.jackson.module.writer.WriterPreferences;
10+
11+
/**
12+
* {@link java2typescript.jackson.module.grammar.base.AbstractType} that has name, like classes/interfaces,
13+
* but instead of body the type has declared value.
14+
* <p>
15+
* For example
16+
* `type NumberOrString = number | string`
17+
* that can be expressed with
18+
* <p>
19+
* `new TypeDeclarationType("NumberOrString", "number | string")`
20+
*
21+
* @author Ats Uiboupin
22+
*/
23+
public class TypeDeclarationType extends AbstractNamedType {
24+
25+
private String typeScriptType;
26+
27+
public TypeDeclarationType(String className, String typeScriptType) {
28+
super(className);
29+
this.typeScriptType = typeScriptType;
30+
}
31+
32+
@Override
33+
public void writeDefInternal(Writer writer, WriterPreferences preferences) throws IOException {
34+
// TODO separate writer for this type
35+
writer.write(format("type %s = %s;", name, typeScriptType));
36+
}
37+
38+
}

java2typescript-jackson/src/main/java/java2typescript/jackson/module/visitors/TSJsonObjectFormatVisitor.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java2typescript.jackson.module.grammar.AnyType;
2828
import java2typescript.jackson.module.grammar.FunctionType;
2929
import java2typescript.jackson.module.grammar.ClassType;
30+
import java2typescript.jackson.module.grammar.TypeDeclarationType;
3031
import java2typescript.jackson.module.grammar.VoidType;
3132
import java2typescript.jackson.module.grammar.base.AbstractType;
3233

@@ -161,6 +162,10 @@ protected AbstractType getTSTypeForProperty(BeanProperty writer) throws JsonMapp
161162

162163
AbstractType customType = conf.getCustomTypes().get(type.getRawClass().getName());
163164
if(customType != null) {
165+
if(customType instanceof TypeDeclarationType) {
166+
TypeDeclarationType tdt = (TypeDeclarationType) customType;
167+
getModule().getNamedTypes().put(tdt.getName(), tdt);
168+
}
164169
return customType;
165170
}
166171

java2typescript-jackson/src/test/java/java2typescript/jackson/module/CustomTypeDefinitionGeneratorTest.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919
import java.io.IOException;
2020
import java.io.StringWriter;
2121
import java.io.Writer;
22+
import java.util.Date;
2223

2324
import org.junit.Test;
2425

2526
import java2typescript.jackson.module.grammar.Module;
27+
import java2typescript.jackson.module.grammar.TypeDeclarationType;
2628
import java2typescript.jackson.module.grammar.base.AbstractPrimitiveType;
2729
import java2typescript.jackson.module.util.ExpectedOutputChecker;
2830
import java2typescript.jackson.module.util.TestUtil;
@@ -36,6 +38,15 @@ class TestClass {
3638
}
3739

3840
public class CustomDate {
41+
public Date value;
42+
}
43+
44+
public class LongValueAddedDirectlyToModule {
45+
public Long value;
46+
}
47+
48+
public class Unused {
49+
public Long value;
3950
}
4051

4152
public static class DateType extends AbstractPrimitiveType {
@@ -66,4 +77,25 @@ public void classWithCustomTypeFields() throws IOException {
6677
// Assert
6778
ExpectedOutputChecker.checkOutputFromFile(out);
6879
}
80+
81+
@Test
82+
public void declareTypeInsteadOfEmittingInterface() throws IOException {
83+
// Arrange
84+
Configuration conf = new Configuration()
85+
.addType(CustomDate.class, new TypeDeclarationType("DateStringOrNumber", "string | number"))
86+
.addType(LongValueAddedDirectlyToModule.class, new TypeDeclarationType("NumericValue", "number"))
87+
.addType(Unused.class, new TypeDeclarationType("Unused", "shouldNotBeEmitted"));
88+
Module module = TestUtil.createTestModule(conf, TestClass.class, LongValueAddedDirectlyToModule.class);
89+
Writer out = new StringWriter();
90+
91+
// Act
92+
new ExternalModuleFormatWriter().write(module, out);
93+
out.close();
94+
System.out.println(out);
95+
96+
// Assert
97+
ExpectedOutputChecker.checkOutputFromFile(out);
98+
}
99+
100+
69101
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export interface TestClass {
2+
customDate: DateStringOrNumber;
3+
customDateArray: DateStringOrNumber[];
4+
}
5+
6+
export type DateStringOrNumber = string | number;
7+
8+
export type NumericValue = number;

0 commit comments

Comments
 (0)