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
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ In Maven build you can use `typescript-generator-maven-plugin` like this:
</execution>
</executions>
<configuration>
<jsonLibrary>jackson2</jsonLibrary>
<jsonLibrary>jackson3</jsonLibrary>
<classes>
<class>cz.habarta.typescript.generator.Person</class>
</classes>
Expand All @@ -95,7 +95,7 @@ plugins {
}

generateTypeScript {
jsonLibrary = 'jackson2'
jsonLibrary = 'jackson3'
classes = [
'cz.habarta.typescript.generator.sample.Person'
]
Expand All @@ -117,7 +117,7 @@ plugins {

tasks {
generateTypeScript {
jsonLibrary = JsonLibrary.jackson2
jsonLibrary = JsonLibrary.jackson3
outputKind = TypeScriptOutputKind.module
outputFileType = TypeScriptFileType.implementationFile
...
Expand Down Expand Up @@ -214,7 +214,7 @@ ModelParser ==> ModelCompiler ==> Emitter
- `ModelParser` reads Java JSON classes and their properties using Java reflections and creates `Model`.
It uses `TypeProcessor`s for finding used classes.
For example if property type is `List<Person>` it discovers that `Person` class should be also parsed.
`ModelParser`s are specific for each JSON library (for example `Jackson2Parser`).
`ModelParser`s are specific for each JSON library (for example `Jackson3Parser`).
- `ModelCompiler` transforms Java model to TypeScript model (`Model` class to `TsModel` class).
It uses `TypeProcessor`s for mapping Java types to TypeScript types (for example for `int` returns `number`).
- `Emitter` takes `TsModel` and produces TypeScript declaration file.
Expand Down
9 changes: 8 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,14 @@
<dependency>
<groupId>com.fasterxml.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>2.15.2</version>
<version>2.20.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>tools.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>3.0.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Expand Down
22 changes: 22 additions & 0 deletions typescript-generator-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
</dependency>
<dependency>
<groupId>tools.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>tools.jackson.module</groupId>
<artifactId>jackson-module-jakarta-xmlbind-annotations</artifactId>
</dependency>
<dependency>
<groupId>tools.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
Expand Down Expand Up @@ -183,6 +195,11 @@
<artifactId>jackson-datatype-guava</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>tools.jackson.datatype</groupId>
<artifactId>jackson-datatype-guava</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
Expand All @@ -194,6 +211,11 @@
<artifactId>jackson-datatype-joda</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>tools.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.vavr</groupId>
<artifactId>vavr</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package cz.habarta.typescript.generator;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import java.util.List;

/**
* This class is used for configuration in Maven and Gradle plugins
* so we need to pay attention to use only types supported in both build plugins.
*/
public class Jackson3Configuration {

/**
* Minimum visibility required for fields to be auto-detected.
*/
public JsonAutoDetect.Visibility fieldVisibility;

/**
* Minimum visibility required for getters to be auto-detected (doesn't include "is getters").
*/
public JsonAutoDetect.Visibility getterVisibility;

/**
* Minimum visibility required for "is getters" to be auto-detected.
*/
public JsonAutoDetect.Visibility isGetterVisibility;

/**
* Minimum visibility required for setters to be auto-detected.
*/
public JsonAutoDetect.Visibility setterVisibility;

/**
* Minimum visibility required for creators to be auto-detected.
*/
public JsonAutoDetect.Visibility creatorVisibility;

/**
* Shape format overrides for specified classes.
* Multiple overrides can be specified, each using this format: <code>javaClassName:shape</code>
* where shape is one of the values from
* <a href="https://github.com/FasterXML/jackson-annotations/blob/master/src/main/java/com/fasterxml/jackson/annotation/JsonFormat.java">JsonFormat.Shape</a> enum.
* Example: <code>java.util.Map$Entry:OBJECT</code>
*/
public List<String> shapeConfigOverrides;

/**
* Feature that determines standard Enum values representation:
* if enabled, return value of <code>Enum.toString()</code> is used;
* if disabled, return value of <code>Enum.name()</code> is used.<br>
* (In <code>ObjectMapper</code> this feature is controlled using
* <code>SerializationFeature.WRITE_ENUMS_USING_TO_STRING</code> and
* <code>DeserializationFeature.READ_ENUMS_USING_TO_STRING</code> constants.)<br>
* Default value is <code>false</code>.
*/
public boolean enumsUsingToString;

/**
* Disables processing of <code>@JsonIdentityInfo</code> and <code>@JsonIdentityReference</code> annotations.
* Can be useful for example when using JSOG library which uses IDs to serialize and deserialize object graphs.
*/
public boolean disableObjectIdentityFeature;

/**
* Types produced by <code>JsonSerializer</code>s.
* Multiple mappings can be specified, each using following format: <code>serializerClassName:typescriptType</code>.
* Example: <code>org.example.IdSerializer:string</code> or <code>org.example.IdSerializer:{ id: string }</code>
*/
public List<String> serializerTypeMappings;

/**
* Types produced by <code>JsonDeserializer</code>s.
* Multiple mappings can be specified, each using following format: <code>deserializerClassName:typescriptType</code>.
* Example: <code>org.example.MyDeserializer:string</code>
*/
public List<String> deserializerTypeMappings;

/**
* Specifies ObjectMapper's active view (as a fully-qualified class name).
* Properties can be annotated with <code>@JsonView</code> to indicate which views they are part of.
*/
public String view;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package cz.habarta.typescript.generator;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import tools.jackson.databind.ValueDeserializer;
import tools.jackson.databind.ValueSerializer;

public class Jackson3ConfigurationResolved {

public JsonAutoDetect.Visibility fieldVisibility;
public JsonAutoDetect.Visibility getterVisibility;
public JsonAutoDetect.Visibility isGetterVisibility;
public JsonAutoDetect.Visibility setterVisibility;
public JsonAutoDetect.Visibility creatorVisibility;
public Map<Class<?>, JsonFormat.Shape> shapeConfigOverrides;
public boolean enumsUsingToString;
public boolean disableObjectIdentityFeature;
@SuppressWarnings("rawtypes")
public Map<Class<? extends ValueSerializer>, String> serializerTypeMappings;
@SuppressWarnings("rawtypes")
public Map<Class<? extends ValueDeserializer>, String> deserializerTypeMappings;
public Class<?> view;

public static Jackson3ConfigurationResolved from(Jackson3Configuration configuration, ClassLoader classLoader) {
final Jackson3ConfigurationResolved resolved = new Jackson3ConfigurationResolved();
resolved.fieldVisibility = configuration.fieldVisibility;
resolved.getterVisibility = configuration.getterVisibility;
resolved.isGetterVisibility = configuration.isGetterVisibility;
resolved.setterVisibility = configuration.setterVisibility;
resolved.creatorVisibility = configuration.creatorVisibility;
resolved.fieldVisibility = configuration.fieldVisibility;
resolved.shapeConfigOverrides = resolveClassMappings(
configuration.shapeConfigOverrides, "shapeConfigOverride", classLoader, Object.class, JsonFormat.Shape::valueOf);
resolved.enumsUsingToString = configuration.enumsUsingToString;
resolved.disableObjectIdentityFeature = configuration.disableObjectIdentityFeature;
resolved.deserializerTypeMappings = resolveClassMappings(
configuration.deserializerTypeMappings, "deserializerTypeMapping", classLoader, ValueDeserializer.class, Function.identity());
resolved.serializerTypeMappings = resolveClassMappings(
configuration.serializerTypeMappings, "serializerTypeMapping", classLoader, ValueSerializer.class, Function.identity());
resolved.view = configuration.view != null ? Settings.loadClass(classLoader, configuration.view, Object.class) : null;
return resolved;
}

private static <C, V> Map<Class<? extends C>, V> resolveClassMappings(List<String> mappings, String mappingName, ClassLoader classLoader,
Class<? extends C> key, Function<String, V> valueConvertor) {
if (mappings == null) {
return null;
}
final Map<Class<? extends C>, V> resolvedMappings = new LinkedHashMap<>();
final Map<String, String> mappingsMap = Settings.convertToMap(mappings, mappingName);
for (Map.Entry<String, String> entry : mappingsMap.entrySet()) {
final Class<? extends C> cls = Settings.loadClass(classLoader, entry.getKey(), key);
final V value = valueConvertor.apply(entry.getValue());
resolvedMappings.put(cls, value);
}
return resolvedMappings;
}

public void setVisibility(
JsonAutoDetect.Visibility fieldVisibility,
JsonAutoDetect.Visibility getterVisibility,
JsonAutoDetect.Visibility isGetterVisibility,
JsonAutoDetect.Visibility setterVisibility,
JsonAutoDetect.Visibility creatorVisibility) {
this.fieldVisibility = fieldVisibility;
this.getterVisibility = getterVisibility;
this.isGetterVisibility = isGetterVisibility;
this.setterVisibility = setterVisibility;
this.creatorVisibility = creatorVisibility;
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package cz.habarta.typescript.generator;

public enum JsonLibrary {
jackson2, jaxb, gson, jsonb
jackson2, jackson3, jaxb, gson, jsonb
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import tools.jackson.databind.JacksonModule;


/**
Expand All @@ -59,6 +60,7 @@ public class Settings {
private LoadedModuleDependencies loadedModuleDependencies = null;
public JsonLibrary jsonLibrary = null;
public Jackson2ConfigurationResolved jackson2Configuration = null;
public Jackson3ConfigurationResolved jackson3Configuration = null;
public GsonConfiguration gsonConfiguration = null;
public JsonbConfiguration jsonbConfiguration = null;
public List<String> additionalDataLibraries = new ArrayList<>();
Expand Down Expand Up @@ -135,6 +137,8 @@ public class Settings {
public String npmBuildScript = null;
public boolean jackson2ModuleDiscovery = false;
public List<Class<? extends Module>> jackson2Modules = new ArrayList<>();
public boolean jackson3ModuleDiscovery = false;
public List<Class<? extends JacksonModule>> jackson3Modules = new ArrayList<>();
public ClassLoader classLoader = null;

private boolean defaultStringEnumsOverriddenByExtension = false;
Expand Down Expand Up @@ -221,6 +225,12 @@ public void setJackson2Configuration(ClassLoader classLoader, Jackson2Configurat
}
}

public void setJackson3Configuration(ClassLoader classLoader, Jackson3Configuration configuration) {
if (configuration != null) {
jackson3Configuration = Jackson3ConfigurationResolved.from(configuration, classLoader);
}
}

public void loadCustomTypeProcessor(ClassLoader classLoader, String customTypeProcessor) {
if (customTypeProcessor != null) {
this.customTypeProcessor = loadInstance(classLoader, customTypeProcessor, TypeProcessor.class);
Expand Down Expand Up @@ -274,6 +284,10 @@ public void loadJackson2Modules(ClassLoader classLoader, List<String> jackson2Mo
this.jackson2Modules = loadClasses(classLoader, jackson2Modules, Module.class);
}

public void loadJackson3Modules(ClassLoader classLoader, List<String> jackson3Modules) {
this.jackson3Modules = loadClasses(classLoader, jackson3Modules, JacksonModule.class);
}

public static Map<String, String> convertToMap(List<String> items, String itemName) {
final Map<String, String> result = new LinkedHashMap<>();
if (items != null) {
Expand Down Expand Up @@ -319,6 +333,9 @@ public void validate() {
if (jackson2Configuration != null && jsonLibrary != JsonLibrary.jackson2) {
throw new RuntimeException("'jackson2Configuration' parameter is only applicable to 'jackson2' library.");
}
if (jackson3Configuration != null && jsonLibrary != JsonLibrary.jackson3) {
throw new RuntimeException("'jackson3Configuration' parameter is only applicable to 'jackson3' library.");
}
if (!generateNpmPackageJson && (!npmPackageDependencies.isEmpty() || !npmDevDependencies.isEmpty() || !npmPeerDependencies.isEmpty())) {
throw new RuntimeException("'npmDependencies', 'npmDevDependencies' and 'npmPeerDependencies' parameters are only applicable when generating NPM 'package.json'.");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import cz.habarta.typescript.generator.emitter.TsModel;
import cz.habarta.typescript.generator.parser.GsonParser;
import cz.habarta.typescript.generator.parser.Jackson2Parser;
import cz.habarta.typescript.generator.parser.Jackson3Parser;
import cz.habarta.typescript.generator.parser.JsonbParser;
import cz.habarta.typescript.generator.parser.Model;
import cz.habarta.typescript.generator.parser.ModelParser;
Expand Down Expand Up @@ -188,6 +189,8 @@ private ModelParser createModelParser() {

private ModelParser.Factory getModelParserFactory() {
switch (settings.jsonLibrary) {
case jackson3:
return new Jackson3Parser.Jackson3ParserFactory();
case jackson2:
return new Jackson2Parser.Jackson2ParserFactory();
case jaxb:
Expand Down
Loading