Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions java2typescript-jackson/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,23 @@ new Configuration().addType(CustomDate.class, DateType.getInstance())

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


##### Emitting `declare type SomeTypeName = SomeOtherTypeOrTypeExpression` instead of interface
There are cases where instead of asking to emit TypeScript interface for specific Java type,
You might want to specify the TypeScript type declaration
(with potentially different type name)
to be used instead of the interface of the Java type. Here is an example:

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:
```TypeScript
type DateWithoutTime = string | number;
```
This could be accomplished using custom configuration:
```Java
Configuration conf = new Configuration()
.addType(LocalDate.class, new TypeDeclarationType("DateWithoutTime", "string | number"));
```
There are more use-cases for this solution - see
[the description of the issue](https://github.com/raphaeljolivet/java2typescript/issues/76)
and the test [source](src/test/java/java2typescript/jackson/module/CustomTypeDefinitionGeneratorTest.java#L82)
and [output](src/test/resources/java2typescript/jackson/module/CustomTypeDefinitionGeneratorTest.classWithCustomTypeFields.d.ts) as an example.
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,16 @@
package java2typescript.jackson.module;

import java.util.Collection;
import java2typescript.jackson.module.grammar.Module;
import java2typescript.jackson.module.visitors.TSJsonFormatVisitorWrapper;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.SimpleType;

import java2typescript.jackson.module.grammar.Module;
import java2typescript.jackson.module.grammar.TypeDeclarationType;
import java2typescript.jackson.module.grammar.base.AbstractType;
import java2typescript.jackson.module.visitors.TSJsonFormatVisitorWrapper;

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

for (Class<?> clazz : classes) {
AbstractType customType = conf.getCustomTypes().get(clazz.getName());
if(customType != null && customType instanceof TypeDeclarationType) {
// When the class is registered as TypeDeclarationType, then ...
String tsTypeName = conf.getNamingStrategy().getName(SimpleType.construct(clazz));
// ... add that type to the module ...
module.getNamedTypes().put(tsTypeName, (TypeDeclarationType)customType);
// ... instead of inspecting class body
continue;
}
mapper.acceptJsonFormatVisitor(clazz, visitor);
}
return module;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package java2typescript.jackson.module.grammar;

import static java.lang.String.format;

import java.io.IOException;
import java.io.Writer;

import java2typescript.jackson.module.grammar.base.AbstractNamedType;
import java2typescript.jackson.module.writer.WriterPreferences;

/**
* {@link java2typescript.jackson.module.grammar.base.AbstractType} that has name, like classes/interfaces,
* but instead of body the type has declared value.
* <p>
* For example
* `type NumberOrString = number | string`
* that can be expressed with
* <p>
* `new TypeDeclarationType("NumberOrString", "number | string")`
*
* @author Ats Uiboupin
*/
public class TypeDeclarationType extends AbstractNamedType {

private String typeScriptType;

public TypeDeclarationType(String className, String typeScriptType) {
super(className);
this.typeScriptType = typeScriptType;
}

@Override
public void writeDefInternal(Writer writer, WriterPreferences preferences) throws IOException {
// TODO separate writer for this type
writer.write(format("type %s = %s;", name, typeScriptType));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java2typescript.jackson.module.grammar.AnyType;
import java2typescript.jackson.module.grammar.FunctionType;
import java2typescript.jackson.module.grammar.ClassType;
import java2typescript.jackson.module.grammar.TypeDeclarationType;
import java2typescript.jackson.module.grammar.VoidType;
import java2typescript.jackson.module.grammar.base.AbstractType;

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

AbstractType customType = conf.getCustomTypes().get(type.getRawClass().getName());
if(customType != null) {
if(customType instanceof TypeDeclarationType) {
TypeDeclarationType tdt = (TypeDeclarationType) customType;
getModule().getNamedTypes().put(tdt.getName(), tdt);
}
return customType;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Date;

import org.junit.Test;

import java2typescript.jackson.module.grammar.Module;
import java2typescript.jackson.module.grammar.TypeDeclarationType;
import java2typescript.jackson.module.grammar.base.AbstractPrimitiveType;
import java2typescript.jackson.module.util.ExpectedOutputChecker;
import java2typescript.jackson.module.util.TestUtil;
Expand All @@ -36,6 +38,15 @@ class TestClass {
}

public class CustomDate {
public Date value;
}

public class LongValueAddedDirectlyToModule {
public Long value;
}

public class Unused {
public Long value;
}

public static class DateType extends AbstractPrimitiveType {
Expand Down Expand Up @@ -66,4 +77,25 @@ public void classWithCustomTypeFields() throws IOException {
// Assert
ExpectedOutputChecker.checkOutputFromFile(out);
}

@Test
public void declareTypeInsteadOfEmittingInterface() throws IOException {
// Arrange
Configuration conf = new Configuration()
.addType(CustomDate.class, new TypeDeclarationType("DateStringOrNumber", "string | number"))
.addType(LongValueAddedDirectlyToModule.class, new TypeDeclarationType("NumericValue", "number"))
.addType(Unused.class, new TypeDeclarationType("Unused", "shouldNotBeEmitted"));
Module module = TestUtil.createTestModule(conf, TestClass.class, LongValueAddedDirectlyToModule.class);
Writer out = new StringWriter();

// Act
new ExternalModuleFormatWriter().write(module, out);
out.close();
System.out.println(out);

// Assert
ExpectedOutputChecker.checkOutputFromFile(out);
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export interface TestClass {
customDate: DateStringOrNumber;
customDateArray: DateStringOrNumber[];
}

export type DateStringOrNumber = string | number;

export type NumericValue = number;