Customizing Generation¶
The output generated by tsgen can be customized either by using the TSModule Annotation and/or by command line Parameters. The latter is useful embedding data from the build process, e.g. the version number.
The most relevant customizations are done adding one TSModule Annotation at a package of your compilation unit.
Sometimes a configuration can be placed multiple times, e.g. as compiler argument and as a setting in the TSModule annotation. The precedence of settings for the effective configuration is:
- the default value in the TSModule annotation
- as parameter of a used TSModule annotation
- the arguments for the annotation processor
The TSModule Annotation¶
Currently only one TSModule annotation is permitted in one compilation unit. The annotation must be put to a package Element, like this:
@TSModule(
moduleName = "namespace_test",
nameSpaceMapping = "jts.modules.nsmap -> easy"
)
package jts.modules.nsmap;
import dz.jtsgen.annotations.TSModule;
The following annotation parameters are supported:
- moduleName: The module name of the JavaScript/TypeScript Module.
This must be a java package friendly name. This is a required
parameter, if the
TSModule
annotation is used - additionalTypes: Array of full qualified Java type names, that should additionally be converted (since 0.4.0)
- author: The author number for the package.json file
- authorUrl: The authorURL for the package.json file
- customTypeMappings: Custom Type Mapping for the module, the
default is
{}
- description: the description for the package.json file
- excludes: regular expression to exclude type conversion, default
is:
{"^sun", "^jdk.internal", "^java.lang.Comparable"}
- getterPrefixes: The prefix filter for selecting the properties
by getters. Default is:
{ "get([_a-zA-Z0-9].*)", "is([_a-zA-Z0-9]].*)"}
- generateTypeGuards: Defines if typescript type gards should be generated as well. The default is false (since 0.3.0)
- license: The license for the package.json file
- nameMappingStrategy: The strategy for mapping getters / setters to
member name: The default is
NameMappingStrategy.JACKSON_DEFAULT
(since 0.4.0) - nameSpaceMapping: The name space mapping, the default is
{}
- nameSpaceMappingStrategy: Defines how the default name space is
calculated. Default is
NameSpaceMappingStrategy.ALL_TO_ROOT
(since 0.2.0) - outputType: The type of the output. Default is
OutputType.NAMESPACE_AMBIENT_TYPE
- setterPrefixes: prefix filter for members. Default is
{"set([_a-zA-Z0-9].*)"}
(sine 0.4.0) - version: The version number for the package.json file, default is “1.0.0”
- enumExportStrategy: Defines how the default enum output strategy is. Default is
EnumExportStrategy.NUMERIC
Note: The Processing Parameters tsgen may override some of these settings. See Processing Parameters for details.
Custom Type Mapping¶
The annotation processor supports a simple mapping description language. The custom Type Mapping for the module is a list of strings, each describing a type mapping. Each string consists of a Java Type (canonical name with type params) and the resulting TypeScript Type. Both Types are separated with an arrow, e.g. :
java.util.Date -> IDateJSStatic
maps a java.util.Date
to the TypeScript type IDateJSStatic
It also is possible to use type variables, e.g. :
java.util.List<T> -> Array<T>
will convert any java.util.List or it’s subtypes to an Array type in TypeScript. If the matched java type has a type parameter the converted type parameter will be inserted accordingly.
Because in TypeScript the types Array
and Map
differ from []
or {}
jtsgen is able to embed the type in
a literal way. After the arrow the type variables can be expresed using the back tick character, e.g:
java.util.List<T> -> `T`[]
Limits: There are some constraints using those expressions: it is not possible to express the name spaces at the right hand side in a proper way. jtsgen adds a namespace to the java declaration types. Currently accessing this name space is out of scope.
Default Conversions¶
- The following mappings can not be configured, for now:
- The numerical primitive types are mapped to
number
- The primitive boolean is mapped to
boolean
- An array is mapped to `T`[]
- The numerical primitive types are mapped to
The annotation processor has the following mapping for declaration types configured:
- java.lang.Void -> Void
- java.lang.Object -> Object
- java.lang.String -> string
- java.lang.Character -> string
- java.lang.Number |-> number
- java.lang.Boolean -> boolean
- java.util.Collection<T> -> `T`[]
- java.util.Map<U,V> -> { [key: `U`]: `V`; }
The processor has no knowledge about the the necessary imports.
Mapping-DSL¶
The Mapping DSL defined in ANTLR BNF variant:
mapping : origin whsp* arrow whsp* target;
arrow : '->' | '|->'
origin : jident ( '.' , jident )* tsAngleType?
target : ( jident '.' )* tstypes+
tsLit : tsChar*
tsAngleType : '<' jident ( ',' jident )* '>'
tsLitType : '`' jident '`'
tsTypes : tstype | ( tstype whtsp )*
tsType : tsLit | tsangletype | tslittype | whtsp
jident : ('a'-'z' | 'A' - 'Z' | '_' ) ('a'-'z' | 'A' - 'Z' | '_' | '0' - '9')*
tsChar : * all chars expecpt '<' | '>' | '`' *
Name Space Mapping¶
TSModule accepts a list of name spaces, that should me mapped (shortened). That list will be prepended to the calculated name space mapping. The following name spave mapping strategies are available:
TOP_LEVEL_TO_ROOT
: The top level java types are mapped to the root name space. Everything beneath is mapped into name spacesALL_TO_ROOT
: All types are mapped to the root name space, only the types of same name reside in their own name spaceMANUAL
: No name space mapping is calculated
Some examples of :
a.b.c ->
: Maps a.b.c (and beneath) to roota.b.c -> a.b
: Maps a.b.c to namespace a=a.b.c ->
: Maps only a.b.c to the root
Output: TypeScript Modules¶
The type of the output can be configured by the outputType parameter of the TSModule annotation:
- NAMESPACE_AMBIENT_TYPE : exports a module with ambient types (d.ts and package.json) with a declared name space
- NAMESPACE_FILE : only the ambient types with namespaces in a single d.ts file
- MODULE : exports a declared module, e.g. using declare module at the top without ambient types
- NO_MODULE : exports a single file containing all converted types without any surrounding namespace or module declaration (since 0.2.0)
Unfortunately the TypeScript team decided to disable access to files outside of the rootDir [TS-9858]. The strategey including the output of tsgen into your frontend project depends on the general project structure. Use one of the following options:
- Publish the generated module to the npmjs compatible repository (local or public). The disadvantage of this it that a an additional release step with a changed version number is needed for npm (or yarn) detecting a change
- Using the npm link feature
- No Module at all and instead copy the output directly into the TypeScript source directory.
Member Detection¶
tsgen detects the members of the converted type using the following rules:
- public non static members of a Java class
- existence of a getter method
By default tsgen adheres to the Java Beans specification [JavaBean], but this behavior can be modified. In the scope of this documentation the definition of getter and setter methods have to be extended to include members, that do not adhere the Java Beans specification, e.g. classes with Boolean properties generated by Kotlin. So:
- a setter method is any method that returns void, accepts exactly one argument. The method name matches the defined setter expression.
- a getter method is any method, that returns a type without any argument. The method name matches the defined getter expression.
To support the property naming conventions in Kotlin [CK] tsgen
does not split getters to Boolean and non-Boolean types (isX,
getX). For simplicity reasons only the following two options in
TSModule
define the getter and setter filter expressions:
- getterPrefixes default:
{ "get([_a-zA-Z0-9].*)", "is([_a-zA-Z0-9]].*)" }
- setterPrefixes default:
{ "set([_a-zA-Z0-9]].*)"}
Both prefixes act as an filter and as a function to extract the raw member of the member. The member name itself is defined by the member name mapping strategy (see next chapter). Only methods, that matches one of the both prefixes are considered as a getter or setter method. The group (that is the regular expression between the braces) extracts the the name which is applied to a name mapping function.
Member Name Mapping¶
The extracted raw member name has to match the one the used by the JSON
framework. For example, in Jackson you define the mapping of the
member names using a PropertyNamingStrategy [PNS]. tsgen tries to stick to
the default setting of Jackson’s DataBind. If necessary you can change this
name mapping in tsgen by setting the nameMappingStrategy
in TSModule
to one of the following strategy:
JACKSON_DEFAULT
: the default Jackson property name mapping. This is the default used in tsgenSIMPLE
: no mapping at allSNAKE_CASE
: upper cases are interpreted as words that will be transformed to lower case words separated by underscoresUPPER_CAMEL_CASE
: The first character is converted to upper case
The member name mapping strategy can be defined using the
parameter nameMappingStrategy
of the TSModule
annotation.
Enum Output Strategy¶
NUMERIC
: Writing numeric enums. This is the default used in tsgenSTRING
: Writing string enums.