diff --git a/core/pom.xml b/core/pom.xml new file mode 100644 index 0000000..9405746 --- /dev/null +++ b/core/pom.xml @@ -0,0 +1,10 @@ + + 4.0.0 + + org.bsc.processor + java2ts-processor-parent + 1.0.0-SNAPSHOT + + java2ts-processor-core + java2ts-processor::core - ${project.version} + \ No newline at end of file diff --git a/processor/src/main/java/org/bsc/processor/TSType.java b/core/src/main/java/org/bsc/java2typescript/TSType.java similarity index 63% rename from processor/src/main/java/org/bsc/processor/TSType.java rename to core/src/main/java/org/bsc/java2typescript/TSType.java index c532f30..d420936 100644 --- a/processor/src/main/java/org/bsc/processor/TSType.java +++ b/core/src/main/java/org/bsc/java2typescript/TSType.java @@ -1,6 +1,13 @@ -package org.bsc.processor; +package org.bsc.java2typescript; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.HashMap; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** @@ -45,7 +52,7 @@ public static TSType functional( Class cl, String alias ) { }}; } - protected static TSType from( Class cl ) { + public static TSType from( Class cl ) { return new TSType() {{ put( "value", cl); }}; } @@ -115,6 +122,45 @@ public final String getTypeName() { public final String getSimpleTypeName() { return (hasAlias()) ? getAlias() : getValue().getSimpleName(); } + + /** + * + * @param type + * @return + */ + public Set getFields() { + + final Predicate std = f -> + !f.isSynthetic() && + Modifier.isPublic( f.getModifiers() ) && + Character.isJavaIdentifierStart(f.getName().charAt(0)) && + f.getName().chars().skip(1).allMatch(Character::isJavaIdentifierPart); + + return Stream.concat( Stream.of(getValue().getFields()), Stream.of(getValue().getDeclaredFields()) ) + .filter(std) + .collect( Collectors.toSet( ) ); + + } + + /** + * + * @param type + * @return + */ + public Set getMethods() { + final Predicate include = m -> + !m.isBridge() && + !m.isSynthetic() && + Modifier.isPublic( m.getModifiers() ) && + Character.isJavaIdentifierStart(m.getName().charAt(0)) && + m.getName().chars().skip(1).allMatch(Character::isJavaIdentifierPart); + + return Stream.concat( Stream.of(getValue().getMethods()), Stream.of(getValue().getDeclaredMethods()) ) + .filter(include) + .collect( Collectors.toSet( ) ); + + } + /** * diff --git a/core/src/main/java/org/bsc/java2typescript/TypescriptConverter.java b/core/src/main/java/org/bsc/java2typescript/TypescriptConverter.java new file mode 100644 index 0000000..21f6a12 --- /dev/null +++ b/core/src/main/java/org/bsc/java2typescript/TypescriptConverter.java @@ -0,0 +1,875 @@ +package org.bsc.java2typescript; + +import static java.lang.String.format; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Parameter; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.lang.reflect.WildcardType; +import java.util.Arrays; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.BiFunction; +import java.util.function.BiPredicate; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class TypescriptConverter { + + final static String ENDL = ";\n"; + + + /** + * + */ + public static BiPredicate, Class> isPackageMatch = (a, b) -> + a.getPackage().equals(b.getPackage()) ; + + /** + * + */ + private static BiFunction,Type, Boolean> typeParameterMatch = (declaringClass, type) -> + ( type instanceof TypeVariable ) ? + Arrays.stream(declaringClass.getTypeParameters()) + .map( (tp) -> tp.getName()) + .anyMatch( name -> name.equals(((TypeVariable)type).getName())) : + false + ; + + private final static void log( String fmt, Object ...args ) { + //System.out.println( format( fmt, (Object[])args)); + } + + private final static void debug( String fmt, Object ...args ) { + System.out.print( "DEBUG: "); + System.out.println( format( fmt, (Object[])args)); + } + + /** + * + * @param type + * @return + */ + public static final String processFunctionalInterface( TSType type ) { + Objects.requireNonNull(type, "argument 'type' is not defined!"); + + return null; + } + + /** + * + * @param type + * @param alias + * @return + */ + public static final String getAliasDeclaration( Class type, String alias ) { + Objects.requireNonNull(type, "argument 'type' is not defined!"); + Objects.requireNonNull(alias, "argument 'alias' is not defined!"); + + final TypeVariable[] typeParameters = type.getTypeParameters(); + + if( typeParameters!=null && typeParameters.length > 0 ) { + + final String pp = Arrays.stream(typeParameters).map( tp -> tp.getName() ).collect( Collectors.joining(",","<", ">")); + return format( "type %s%s = %s%s;\n\n", alias, pp, type.getName(), pp ); + + } + + return format( "type %s = %s;\n\n", alias, type.getName() ); + } + + /** + * + * @param p + * @return + */ + public static final String getParameterName( Parameter p ) { + final String name = p.getName(); + + switch( name ) { + case "function": + return "func"; + default: + return name; + } + } + + /** + * + * @param m + * @return + */ + public static boolean isStatic( M m ) { + + final int modifier = m.getModifiers(); + + return (Modifier.isStatic( modifier) && + Modifier.isPublic( modifier )) ; + } + + /** + * + * @param m + * @return + */ + static boolean isFactoryMethod( Method m ) { + + return (isStatic(m) && + m.getReturnType().equals(m.getDeclaringClass())); + } + + + /** + * + * @param type_parameters_list + * @return + */ + static String getClassParametersDecl( java.util.List type_parameters_list ) { + + if( type_parameters_list.isEmpty() ) return ""; + + return format("<%s>", type_parameters_list + .stream() + .collect( Collectors.joining(", ")) ); + } + + /** + * + * @param type + * @param declaringType + * @return + */ + static String getTypeName( TSType type, TSType declaringType, boolean packageResolution ) { + + final java.util.List dc_parameters_list = + Arrays.stream(declaringType.getValue().getTypeParameters()) + .map( (tp) -> tp.getName()) + .collect(Collectors.toList()); + + final java.util.List type_parameters_list = + Arrays.stream(type.getValue().getTypeParameters()) + .map( tp -> (dc_parameters_list.contains(tp.getName()) ) ? tp.getName() : "any" ) + .collect(Collectors.toList()); + + final java.util.List parameters = + dc_parameters_list.size() == type_parameters_list.size() ? dc_parameters_list : type_parameters_list ; + + final Package currentNS = (packageResolution) ? declaringType.getValue().getPackage() : null; + + return new StringBuilder() + .append( + type.getValue().getPackage().equals(currentNS) || type.isFunctionalInterface() ? + type.getSimpleTypeName() : + type.getTypeName() + ) + .append( getClassParametersDecl(parameters) ) + .toString(); + } + + /** + * + * @param type + * @param declaringMember + * @param declaredTypeMap + * @param packageResolution + * @param typeMatch + * @param onTypeMismatch + * @return + */ + public static String convertJavaToTS( Type type, + M declaringMember, + TSType declaringType, + java.util.Map declaredTypeMap, + boolean packageResolution, + Optional>> onTypeMismatch) + { + Objects.requireNonNull(type, "Type argument is null!"); + Objects.requireNonNull(declaringMember, "declaringMethod argument is null!"); + Objects.requireNonNull(declaringType, "declaringType argument is null!"); + Objects.requireNonNull(declaredTypeMap, "declaredTypeMap argument is null!"); + + /** + * + */ + final Predicate> typeMismatch = ( tv ) -> { + if( isStatic(declaringMember) ) return true; + if( declaringMember instanceof Constructor ) return true; + return !typeParameterMatch.apply(declaringType.getValue(), tv ); + }; + + if( type instanceof ParameterizedType ) { + + final ParameterizedType pType = (ParameterizedType) type; + + final Class rawType = (Class)pType.getRawType(); + + final TSType tstype = declaredTypeMap.get(rawType.getName()); + if( tstype==null ) { + return format("any /*%s*/",rawType.getName()); + } + + String result = pType.getTypeName() + .replace( rawType.getName(), tstype.getTypeName()) // use Alias + ; + + if( tstype.isFunctionalInterface() || (packageResolution && isPackageMatch.test(tstype.getValue(), declaringType.getValue())) ) { + result = result.replace( tstype.getTypeName(), tstype.getSimpleTypeName()); + } + + final Type[] typeArgs = pType.getActualTypeArguments(); + + for( Type t : typeArgs ) { + if( t instanceof ParameterizedType ) { + + final String typeName = convertJavaToTS( t, + declaringMember, + declaringType, + declaredTypeMap, + packageResolution, + onTypeMismatch); + log( "Parameterized Type %s - %s", t, typeName ); + result = result.replace( t.getTypeName(), typeName); + + } + else if( t instanceof TypeVariable ) { + + log( "type variable: %s", t ); + + final TypeVariable tv = (TypeVariable)t; + + if( typeMismatch.test(tv)) { + + if( onTypeMismatch.isPresent() ) { + onTypeMismatch.get().accept(tv); + } + else { + final String name = tv.getName(); + result = result.replaceAll( "<"+name, "", "any>") + ; + } + } + continue; + } + else if( t instanceof Class ) { + log( "class: %s", t.getTypeName() ); + + final String name = convertJavaToTS( (Class)t, declaringType, declaredTypeMap, packageResolution); + + final String commented = format("/*%s*/", t.getTypeName()); + result = result.replace( commented, "/*@*/") + .replace(t.getTypeName(), name) + .replace( "/*@*/", commented ) + ; + } + else if( t instanceof WildcardType ) { + final WildcardType wt = (WildcardType) t; + + final Type[] lb = wt.getLowerBounds(); + final Type[] ub = wt.getUpperBounds(); + + log( "Wildcard Type : %s lb:%d up:%d", type.getTypeName(), lb.length, ub.length ); + + if( lb.length <= 1 && ub.length==1) { + final Type tt = (lb.length==1) ? lb[0] : ub[0]; + + final String s = convertJavaToTS( tt, + declaringMember, + declaringType, + declaredTypeMap, + packageResolution, + onTypeMismatch); + + result = result.replace( wt.getTypeName(), s); + + // CHECK FOR NESTED WILDCARDTYPE + if( tt instanceof ParameterizedType && + Stream.of((Type[])((ParameterizedType)tt).getActualTypeArguments()) + .anyMatch( arg -> (arg instanceof WildcardType) )) + { + final Class clazz = (Class) (((ParameterizedType)tt).getRawType()); + final String typeName = wt.getTypeName().replace( clazz.getName(), clazz.getSimpleName()); + result = result.replace( typeName, s); + } + } + else { + result = result.replace(wt.getTypeName(), format( "any/*%s*/", wt)); + } + } + else if( t instanceof GenericArrayType ) { + throw new IllegalArgumentException( format("type argument <%s> 'GenericArrayType' is a not supported yet!", t)); + } + + } + + return result; + } + else if( type instanceof TypeVariable ) { + log( "class: %s", type.getTypeName() ); + + final TypeVariable tv = (TypeVariable)type; + + if( typeMismatch.test(tv) ) { + + final String name = tv.getName(); + + if( onTypeMismatch.isPresent() ) { + onTypeMismatch.get().accept(tv); + return name; + } + + return format("any/*%s*/", name); + } + + return type.getTypeName(); + } + else if( type instanceof Class ) { + log( "class: %s", type.getTypeName() ); + + final String name = convertJavaToTS( (Class)type, declaringType, declaredTypeMap, packageResolution); + return name; + } + else if( type instanceof WildcardType ) { + throw new IllegalArgumentException( "type 'WildcardType' is a not supported yet!"); + } + else if( type instanceof GenericArrayType ) { + final GenericArrayType t = (GenericArrayType)type; + + final Type componentType = t.getGenericComponentType(); + + log( "generic array type: %s", componentType.getTypeName() ); + + final String tt = convertJavaToTS( componentType, + declaringMember, + declaringType, + declaredTypeMap, + packageResolution, + onTypeMismatch); + return format("[%s]", tt); + + + //return ( typeParameterMatch.apply(declaringType.getValue(), componentType )) ? + // format("[%s]", componentType ) : + // format("[any/*%s*/]", componentType ); + + } + + throw new IllegalArgumentException( "type is a not recognised type!"); + } + + /** + * + * @param type + * @param declaringType + * @param declaredTypeMap + * @param packageResolution + * @return + */ + private static String convertJavaToTS( Class type, + TSType declaringType, + java.util.Map declaredTypeMap, + boolean packageResolution ) + { + + if( type == null ) return "any"; + + if( Void.class.isAssignableFrom(type) || type.equals(Void.TYPE) ) return "void"; + if( Boolean.class.isAssignableFrom(type) || type.equals(Boolean.TYPE) ) return type.isPrimitive() ? "boolean" : "boolean|null" ; + if( Integer.class.isAssignableFrom(type) || type.equals(Integer.TYPE)) return type.isPrimitive() ? "int" : "int|null" ; + if( Long.class.isAssignableFrom(type) || type.equals(Long.TYPE)) return type.isPrimitive() ? "long" : "long|null" ; + if( Float.class.isAssignableFrom(type) || type.equals(Float.TYPE)) return type.isPrimitive() ? "float" : "float|null" ; + if( Double.class.isAssignableFrom(type) || type.equals(Double.TYPE)) return type.isPrimitive() ? "double" : "double|null" ; + if( Integer.class.isAssignableFrom(type) || type.equals(Integer.TYPE)) return type.isPrimitive() ? "int" : "int|null" ; + if( String.class.isAssignableFrom(type) ) return "string"; + + if( char[].class.equals(type) ) return "chararray"; + if( byte[].class.equals(type) ) return "bytearray"; + + if( type.isArray()) { + return format( "[%s]", convertJavaToTS(type.getComponentType(), declaringType, declaredTypeMap,packageResolution)); + } + + final TSType tt = declaredTypeMap.get( type.getName() ); + if( tt!=null ) { + return getTypeName(tt, declaringType, packageResolution); + } + + return format("any /*%s*/",type.getName()); + + } + + /** + * + * @param keyExtractor + * @return + */ + public static Predicate distinctByKey(Function keyExtractor) { + Map seen = new ConcurrentHashMap<>(); + return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null; + } + + /** + * + * @param declaredClass + * @return + */ + public String processStatic( TSType type, java.util.Map declaredTypeMap ) { + + final Context ctx = new Context( type, declaredTypeMap); + + ctx.append("interface ") + .append( ctx.type.getSimpleTypeName() ) + .append("Static {\n\n") + ; + + ctx.processEnumType(); + + //Append class property + ctx.append("\treadonly class:any;\n"); + + Stream.of(ctx.type.getValue().getConstructors()) + .filter( c -> Modifier.isPublic(c.getModifiers()) ) + .forEach( c -> { + ctx.append("\tnew") + .append( getMethodParametersAndReturnDecl( ctx, c, false) ) + .append(ENDL); + } + ); + + final java.util.Set methodSet = + ctx.type.getMethods() + .stream() + .filter( TypescriptConverter::isStatic ) + .collect( Collectors.toCollection(() -> new java.util.LinkedHashSet<>() )); + + if( !methodSet.isEmpty() ) { + + methodSet.stream() + .sorted( (a,b) -> a.getName().compareTo(b.getName())) + .forEach( md -> + ctx.append( '\t' ) + .append(md.getName()) + .append( getMethodParametersAndReturnDecl( ctx, md, false) ) + .append( ENDL )) + ; + } + + ctx.append( "}\n\n" ) + .append("export const ") + .append(ctx.type.getSimpleTypeName()) + .append(": ") + .append(ctx.type.getSimpleTypeName()) + .append("Static = Java.type(\"") + .append( ctx.type.getValue().getName() ) + .append("\")") + .append( ENDL ) + .append("\n\n") + ; + + return ctx.toString(); + } + + /** + * + * @param m + * @param type + * @param declaredTypeMap + * @param packageResolution + * @return + */ + public String getMethodParametersAndReturnDecl( + E m, + TSType type, + java.util.Map declaredTypeMap, + boolean packageResolution ) + { + final Context ctx = new Context(type, declaredTypeMap); + + return getMethodParametersAndReturnDecl(ctx, m, packageResolution); + } + + /** + * + * @param ctx + * @param m + * @param packageResolution + * @return + */ + private String getMethodParametersAndReturnDecl( Context ctx, E m, boolean packageResolution ) + { + final java.util.Set TypeVarSet = new java.util.HashSet<>(5); + + final Consumer> addTypeVar = tv -> TypeVarSet.add(tv.getName()) ; + + final Parameter[] params = m.getParameters(); + + final String params_string = + Arrays.stream(params) + .map( (tp) -> { + + final String name = getParameterName(tp); + + + if( tp.isVarArgs() ) { + + String type = null; + if( tp.getParameterizedType() instanceof GenericArrayType ) { + + type = convertJavaToTS( ((GenericArrayType)tp.getParameterizedType()).getGenericComponentType(), + m, + ctx.type, + ctx.declaredTypeMap, + packageResolution, + Optional.of( addTypeVar )) ; + } + else { + type = convertJavaToTS( tp.getType().getComponentType(), + m, + ctx.type, + ctx.declaredTypeMap, + packageResolution, + Optional.of( addTypeVar )) ; + } + return String.format( "...%s:%s[]", name, type ); + + } + + final String type = convertJavaToTS( tp.getParameterizedType(), + m, + ctx.type, + ctx.declaredTypeMap, + packageResolution, + Optional.of( addTypeVar )) ; + return String.format( "%s:%s", name, type ); + }) + .collect(Collectors.joining(", ")) + ; + + final Type returnType = ( m instanceof Method ) ? + ((Method)m).getGenericReturnType() : + ctx.type.getValue(); + + final String tsReturnType = + convertJavaToTS( returnType, + m, + ctx.type, + ctx.declaredTypeMap, + packageResolution, + Optional.of( addTypeVar )); + + + final StringBuilder result = new StringBuilder(); + + if( !TypeVarSet.isEmpty() ) { + result + .append('<') + .append( TypeVarSet.stream().collect(Collectors.joining(","))) + .append('>'); + } + return result + .append("( ") + .append(params_string) + .append(" ):") + .append(tsReturnType) + .toString(); + } + + /** + * + * @param ctx + * @param m + * @return + */ + private String getMethodDecl( Context ctx, final Method m ) { + + final StringBuilder sb = new StringBuilder(); + + if( Modifier.isStatic(m.getModifiers()) ) { + + if( ctx.type.getValue().isInterface() ) { + sb.append( "// "); + } + + sb.append("static ").append(m.getName()); + } + else { + sb.append(m.getName()); + } + + sb.append( getMethodParametersAndReturnDecl(ctx, m, true) ); + + return sb.toString(); + + } + + /** + * + * @param type + * @param declaredTypeMap + * @return + */ + public String getClassDecl( TSType type, java.util.Map declaredTypeMap ) { + final Context ctx = new Context(type, declaredTypeMap); + + return ctx.getClassDecl().toString(); + + } + + + class Context implements Cloneable { + final TSType type; + final java.util.Map declaredTypeMap; + final StringBuilder sb = new StringBuilder(); + + public Context(TSType type, Map declaredClassMap) { + Objects.requireNonNull(type, "type is null!"); + Objects.requireNonNull(declaredClassMap, "declaredClassMap is null!"); + + this.type = type; + this.declaredTypeMap = declaredClassMap; + } + + /** + * + * @param cs + * @return + */ + Context append( CharSequence cs ) { + sb.append(cs); + return this; + } + + /** + * + * @param ch + * @return + */ + Context append( char ch ) { + sb.append(ch); + return this; + } + + /** + * + * @return + */ + Context getClassDecl() + { + + final StringBuilder inherited = new StringBuilder(); + + if( type.getValue().isInterface() ) { + sb.append( "interface "); + } + else { + + if( type.getValue().isEnum() ) sb.append( "/* enum */" ); + + sb.append( "class "); + + final TSType superclass = TSType.from(type.getValue().getSuperclass()); + + if( superclass!=null ) { + inherited + .append( " extends ") + .append( getTypeName(superclass, type, true) ) + ; + } + } + + final Class[] interfaces = type.getValue().getInterfaces(); + + if(interfaces.length > 0 ) { + + final String ifc = Arrays.stream(interfaces) + .map( c -> TSType.from(c) ) + .map( t -> getTypeName(t, type, true) ) + .collect( Collectors.joining(", ")) + ; + inherited + .append( (type.getValue().isInterface()) ? " extends " : " implements ") + .append( ifc ) + ; + + + } + + sb.append( getTypeName(type, type, true) ); + + if( inherited.length()>0 ) { + + sb.append("/*") + .append( inherited ) + .append("*/"); + } + + sb.append( " {"); + + return this; + } + + /** + * + * @return + */ + Context processEnumDecl() { + if( type.getValue().isEnum() ) { + type.setExport(true); // force export + Arrays.stream( type.getValue().getEnumConstants() ) + .forEach( (c) -> + sb.append( '\t' ) + .append( "// ") + .append( c.toString() ) + .append( ':') + .append( type.getSimpleTypeName() ) + .append( ';' ) + .append( '\n' ) + ); + sb.append('\n'); + } + + return this; + + } + + /** + * + * @param sb + * @param type + * @param declaredTypeMap + */ + Context processNestedClasses( int level ) { + + final Class nestedClasses[] = type.getValue().getClasses(); + + if( nestedClasses.length == 0 ) return this; + + sb.append( "export module " ) + .append(type.getSimpleTypeName()) + .append(" {\n\n") + ; + + Stream.of(nestedClasses) + .filter( distinctByKey( c -> c.getSimpleName() ) ) + .map( cl -> TSType.from(cl) ) + .map( t -> processClass( level + 1, t, declaredTypeMap) ) + .forEach( decl -> sb.append(decl) ); + + sb.append("\n} // end module ") + .append(type.getSimpleTypeName()) + .append('\n') + ; + return this; + } + + + private Context processEnumType( ) { + + if( type.getValue().isEnum() ) { + Arrays.stream( type.getValue().getEnumConstants() ) + .forEach( (c) -> + sb.append( '\t' ) + .append( c.toString() ) + .append( ':') + .append( type.getTypeName() ) + .append( ';' ) + .append( '\n' ) + ); + sb.append('\n'); + } + + return this; + + } + + + public Context clone() { + return new Context(type, declaredTypeMap); + } + /** + * + */ + @Override + public String toString() { + return sb.toString(); + } + + + } + + + /** + * + * @param bi + * @param declaredTypeMap + * @return + */ + public String processClass( int level, TSType tstype, java.util.Map declaredTypeMap ) { + + final Context ctx = new Context( tstype, declaredTypeMap); + + final String namespace = tstype.getValue().getPackage().getName(); + + if( !tstype.getValue().isMemberClass() ) + ctx.append( "declare namespace " ) + .append(namespace) + .append(" {\n\n") + ; + + ctx.getClassDecl().append("\n\n"); + + ctx.processEnumDecl(); + + final java.util.Set methodSet = + tstype.getMethods() + .stream() + .filter( md -> (tstype.isExport() && isStatic(md))==false ) + .filter( (md) -> { + final String name = md.getName(); + return !( name.contains("$") || // remove unnamed + name.equals("getClass") || + name.equals("hashCode") || + name.equals("wait") || + name.equals("notify") || + name.equals("notifyAll") ); + }) + .collect( Collectors.toCollection(() -> new java.util.LinkedHashSet() )); + + methodSet.stream() + .map( md -> getMethodDecl(ctx, md) ) + .sorted().forEach( (decl) -> + ctx.append( '\t' ) + .append(decl) + .append( ENDL )) + ; + + ctx.append("\n} // end ") + .append(tstype.getSimpleTypeName()) + .append('\n'); + + // NESTED CLASSES + if( level == 0 ) ctx.processNestedClasses( level ); + + if( !tstype.getValue().isMemberClass() ) + ctx.append("\n} // end namespace ") + .append( namespace ) + .append('\n'); + + return ctx.toString(); + + } + +} diff --git a/pom.xml b/pom.xml index 14d9f62..6474b6c 100644 --- a/pom.xml +++ b/pom.xml @@ -70,7 +70,8 @@ - + core + diff --git a/processor/pom.xml b/processor/pom.xml index 43eeba6..953dd18 100644 --- a/processor/pom.xml +++ b/processor/pom.xml @@ -35,5 +35,12 @@ javax.json true + + + ${project.groupId} + java2ts-processor-core + ${project.version} + + diff --git a/processor/src/main/java/org/bsc/processor/TypescriptHelper.java b/processor/src/main/java/org/bsc/processor/TypescriptHelper.java deleted file mode 100644 index fd4574b..0000000 --- a/processor/src/main/java/org/bsc/processor/TypescriptHelper.java +++ /dev/null @@ -1,465 +0,0 @@ -package org.bsc.processor; - -import static java.lang.String.format; - -import java.lang.reflect.Constructor; -import java.lang.reflect.GenericArrayType; -import java.lang.reflect.Member; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.Parameter; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; -import java.lang.reflect.WildcardType; -import java.util.Arrays; -import java.util.Objects; -import java.util.Optional; -import java.util.function.BiFunction; -import java.util.function.BiPredicate; -import java.util.function.Consumer; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class TypescriptHelper { - - /** - * - */ - public static BiPredicate, Class> isPackageMatch = (a, b) -> - a.getPackage().equals(b.getPackage()) ; - - /** - * - */ - private static BiFunction,Type, Boolean> typeParameterMatch = (declaringClass, type) -> - ( type instanceof TypeVariable ) ? - Arrays.stream(declaringClass.getTypeParameters()) - .map( (tp) -> tp.getName()) - .anyMatch( name -> name.equals(((TypeVariable)type).getName())) : - false - ; - - private final static void log( String fmt, Object ...args ) { - //System.out.println( format( fmt, (Object[])args)); - } - - private final static void debug( String fmt, Object ...args ) { - System.out.print( "DEBUG: "); - System.out.println( format( fmt, (Object[])args)); - } - - public static final String processFunctionalInterface( TSType type ) { - Objects.requireNonNull(type, "argument 'type' is not defined!"); - - return null; - } - - /** - * - * @param type - * @param alias - * @return - */ - public static final String getAliasDeclaration( Class type, String alias ) { - Objects.requireNonNull(type, "argument 'type' is not defined!"); - Objects.requireNonNull(alias, "argument 'alias' is not defined!"); - - final TypeVariable[] typeParameters = type.getTypeParameters(); - - if( typeParameters!=null && typeParameters.length > 0 ) { - - final String pp = Arrays.stream(typeParameters).map( tp -> tp.getName() ).collect( Collectors.joining(",","<", ">")); - return format( "type %s%s = %s%s;\n\n", alias, pp, type.getName(), pp ); - - } - - return format( "type %s = %s;\n\n", alias, type.getName() ); - } - - /** - * - * @param p - * @return - */ - public static final String getParameterName( Parameter p ) { - final String name = p.getName(); - - switch( name ) { - case "function": - return "func"; - default: - return name; - } - } - - /** - * - * @param m - * @return - */ - static boolean isStatic( M m ) { - - final int modifier = m.getModifiers(); - - return (Modifier.isStatic( modifier) && - Modifier.isPublic( modifier )) ; - } - - /** - * - * @param m - * @return - */ - static boolean isFactoryMethod( Method m ) { - - return (isStatic(m) && - m.getReturnType().equals(m.getDeclaringClass())); - } - - /** - * - * @param type - * @param declaredClassMap - * @param isSuperclassValid - * @return - */ - static StringBuilder getClassDecl( - StringBuilder statement, - TSType tstype, - java.util.Map declaredClassMap ) - { - - final StringBuilder inherited = new StringBuilder(); - - if( tstype.getValue().isInterface() ) { - statement.append( "interface "); - } - else { - - if( tstype.getValue().isEnum() ) statement.append( "/* enum */" ); - statement.append( "class "); - - final TSType superclass = TSType.from(tstype.getValue().getSuperclass()); - - if( superclass!=null ) { - inherited - .append( " extends ") - .append( getTypeName(superclass, tstype, true) ) - ; - } - } - - final Class[] interfaces = tstype.getValue().getInterfaces(); - - if(interfaces.length > 0 ) { - - final String ifc = Arrays.stream(interfaces) - .map( c -> TSType.from(c) ) - .map( t -> getTypeName(t, tstype, true) ) - .collect( Collectors.joining(", ")) - ; - inherited - .append( (tstype.getValue().isInterface()) ? " extends " : " implements ") - .append( ifc ) - ; - - - } - - statement.append( getTypeName(tstype, tstype, true) ); - - if( inherited.length()>0 ) { - - statement.append("/*") - .append( inherited ) - .append("*/"); - } - - return statement.append( " {"); - - - } - - /** - * - * @param type_parameters_list - * @return - */ - static String getClassParametersDecl( java.util.List type_parameters_list ) { - - if( type_parameters_list.isEmpty() ) return ""; - - return format("<%s>", type_parameters_list - .stream() - .collect( Collectors.joining(", ")) ); - } - - /** - * - * @param type - * @param declaringType - * @return - */ - static String getTypeName( TSType type, TSType declaringType, boolean packageResolution ) { - - final java.util.List dc_parameters_list = - Arrays.stream(declaringType.getValue().getTypeParameters()) - .map( (tp) -> tp.getName()) - .collect(Collectors.toList()); - - final java.util.List type_parameters_list = - Arrays.stream(type.getValue().getTypeParameters()) - .map( tp -> (dc_parameters_list.contains(tp.getName()) ) ? tp.getName() : "any" ) - .collect(Collectors.toList()); - - final java.util.List parameters = - dc_parameters_list.size() == type_parameters_list.size() ? dc_parameters_list : type_parameters_list ; - - final Package currentNS = (packageResolution) ? declaringType.getValue().getPackage() : null; - - return new StringBuilder() - .append( - type.getValue().getPackage().equals(currentNS) || type.isFunctionalInterface() ? - type.getSimpleTypeName() : - type.getTypeName() - ) - .append( getClassParametersDecl(parameters) ) - .toString(); - } - - /** - * - * @param type - * @param declaringMember - * @param declaredTypeMap - * @param packageResolution - * @param typeMatch - * @param onTypeMismatch - * @return - */ - public static String convertJavaToTS( Type type, - M declaringMember, - TSType declaringType, - java.util.Map declaredTypeMap, - boolean packageResolution, - Optional>> onTypeMismatch) - { - Objects.requireNonNull(type, "Type argument is null!"); - Objects.requireNonNull(declaringMember, "declaringMethod argument is null!"); - Objects.requireNonNull(declaringType, "declaringType argument is null!"); - Objects.requireNonNull(declaredTypeMap, "declaredTypeMap argument is null!"); - - /** - * - */ - final Predicate> typeMismatch = ( tv ) -> { - if( isStatic(declaringMember) ) return true; - if( declaringMember instanceof Constructor ) return true; - return !typeParameterMatch.apply(declaringType.getValue(), tv ); - }; - - if( type instanceof ParameterizedType ) { - - final ParameterizedType pType = (ParameterizedType) type; - - final Class rawType = (Class)pType.getRawType(); - - final TSType tstype = declaredTypeMap.get(rawType.getName()); - if( tstype==null ) { - return format("any /*%s*/",rawType.getName()); - } - - String result = pType.getTypeName() - .replace( rawType.getName(), tstype.getTypeName()) // use Alias - ; - - if( tstype.isFunctionalInterface() || (packageResolution && isPackageMatch.test(tstype.getValue(), declaringType.getValue())) ) { - result = result.replace( tstype.getTypeName(), tstype.getSimpleTypeName()); - } - - final Type[] typeArgs = pType.getActualTypeArguments(); - - for( Type t : typeArgs ) { - if( t instanceof ParameterizedType ) { - - final String typeName = convertJavaToTS( t, - declaringMember, - declaringType, - declaredTypeMap, - packageResolution, - onTypeMismatch); - log( "Parameterized Type %s - %s", t, typeName ); - result = result.replace( t.getTypeName(), typeName); - - } - else if( t instanceof TypeVariable ) { - - log( "type variable: %s", t ); - - final TypeVariable tv = (TypeVariable)t; - - if( typeMismatch.test(tv)) { - - if( onTypeMismatch.isPresent() ) { - onTypeMismatch.get().accept(tv); - } - else { - final String name = tv.getName(); - result = result.replaceAll( "<"+name, "", "any>") - ; - } - } - continue; - } - else if( t instanceof Class ) { - log( "class: %s", t.getTypeName() ); - - final String name = convertJavaToTS( (Class)t, declaringType, declaredTypeMap, packageResolution); - - final String commented = format("/*%s*/", t.getTypeName()); - result = result.replace( commented, "/*@*/") - .replace(t.getTypeName(), name) - .replace( "/*@*/", commented ) - ; - } - else if( t instanceof WildcardType ) { - final WildcardType wt = (WildcardType) t; - - final Type[] lb = wt.getLowerBounds(); - final Type[] ub = wt.getUpperBounds(); - - log( "Wildcard Type : %s lb:%d up:%d", type.getTypeName(), lb.length, ub.length ); - - if( lb.length <= 1 && ub.length==1) { - final Type tt = (lb.length==1) ? lb[0] : ub[0]; - - final String s = convertJavaToTS( tt, - declaringMember, - declaringType, - declaredTypeMap, - packageResolution, - onTypeMismatch); - - result = result.replace( wt.getTypeName(), s); - - // CHECK FOR NESTED WILDCARDTYPE - if( tt instanceof ParameterizedType && - Stream.of((Type[])((ParameterizedType)tt).getActualTypeArguments()) - .anyMatch( arg -> (arg instanceof WildcardType) )) - { - final Class clazz = (Class) (((ParameterizedType)tt).getRawType()); - final String typeName = wt.getTypeName().replace( clazz.getName(), clazz.getSimpleName()); - result = result.replace( typeName, s); - } - } - else { - result = result.replace(wt.getTypeName(), format( "any/*%s*/", wt)); - } - } - else if( t instanceof GenericArrayType ) { - throw new IllegalArgumentException( format("type argument <%s> 'GenericArrayType' is a not supported yet!", t)); - } - - } - - return result; - } - else if( type instanceof TypeVariable ) { - log( "class: %s", type.getTypeName() ); - - final TypeVariable tv = (TypeVariable)type; - - if( typeMismatch.test(tv) ) { - - final String name = tv.getName(); - - if( onTypeMismatch.isPresent() ) { - onTypeMismatch.get().accept(tv); - return name; - } - - return format("any/*%s*/", name); - } - - return type.getTypeName(); - } - else if( type instanceof Class ) { - log( "class: %s", type.getTypeName() ); - - final String name = convertJavaToTS( (Class)type, declaringType, declaredTypeMap, packageResolution); - return name; - } - else if( type instanceof WildcardType ) { - throw new IllegalArgumentException( "type 'WildcardType' is a not supported yet!"); - } - else if( type instanceof GenericArrayType ) { - final GenericArrayType t = (GenericArrayType)type; - - final Type componentType = t.getGenericComponentType(); - - log( "generic array type: %s", componentType.getTypeName() ); - - final String tt = convertJavaToTS( componentType, - declaringMember, - declaringType, - declaredTypeMap, - packageResolution, - onTypeMismatch); - return format("[%s]", tt); - - - //return ( typeParameterMatch.apply(declaringType.getValue(), componentType )) ? - // format("[%s]", componentType ) : - // format("[any/*%s*/]", componentType ); - - } - - throw new IllegalArgumentException( "type is a not recognised type!"); - } - - /** - * - * @param type - * @param declaringType - * @param declaredTypeMap - * @param packageResolution - * @return - */ - private static String convertJavaToTS( Class type, - TSType declaringType, - java.util.Map declaredTypeMap, - boolean packageResolution ) - { - - if( type == null ) return "any"; - - if( Void.class.isAssignableFrom(type) || type.equals(Void.TYPE) ) return "void"; - if( Boolean.class.isAssignableFrom(type) || type.equals(Boolean.TYPE) ) return type.isPrimitive() ? "boolean" : "boolean|null" ; - if( Integer.class.isAssignableFrom(type) || type.equals(Integer.TYPE)) return type.isPrimitive() ? "int" : "int|null" ; - if( Long.class.isAssignableFrom(type) || type.equals(Long.TYPE)) return type.isPrimitive() ? "long" : "long|null" ; - if( Float.class.isAssignableFrom(type) || type.equals(Float.TYPE)) return type.isPrimitive() ? "float" : "float|null" ; - if( Double.class.isAssignableFrom(type) || type.equals(Double.TYPE)) return type.isPrimitive() ? "double" : "double|null" ; - if( Integer.class.isAssignableFrom(type) || type.equals(Integer.TYPE)) return type.isPrimitive() ? "int" : "int|null" ; - if( String.class.isAssignableFrom(type) ) return "string"; - - if( char[].class.equals(type) ) return "chararray"; - if( byte[].class.equals(type) ) return "bytearray"; - - if( type.isArray()) { - return format( "[%s]", convertJavaToTS(type.getComponentType(), declaringType, declaredTypeMap,packageResolution)); - } - - final TSType tt = declaredTypeMap.get( type.getName() ); - if( tt!=null ) { - return getTypeName(tt, declaringType, packageResolution); - } - - return format("any /*%s*/",type.getName()); - - } - -} diff --git a/processor/src/main/java/org/bsc/processor/TypescriptProcessor.java b/processor/src/main/java/org/bsc/processor/TypescriptProcessor.java index e1bb19f..cdd9c4d 100644 --- a/processor/src/main/java/org/bsc/processor/TypescriptProcessor.java +++ b/processor/src/main/java/org/bsc/processor/TypescriptProcessor.java @@ -1,29 +1,15 @@ package org.bsc.processor; -import static org.bsc.processor.TypescriptHelper.convertJavaToTS; -import static org.bsc.processor.TypescriptHelper.getClassDecl; -import static org.bsc.processor.TypescriptHelper.getParameterName; - import java.io.Closeable; import java.io.IOException; import java.io.Serializable; -import java.lang.reflect.Executable; -import java.lang.reflect.Field; -import java.lang.reflect.GenericArrayType; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.Parameter; -import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.RandomAccess; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.BiPredicate; @@ -34,7 +20,6 @@ import java.util.function.Supplier; import java.util.function.UnaryOperator; import java.util.stream.Collectors; -import java.util.stream.Stream; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedOptions; @@ -46,6 +31,9 @@ import javax.lang.model.element.ExecutableElement; import javax.tools.FileObject; +import org.bsc.java2typescript.TSType; +import org.bsc.java2typescript.TypescriptConverter; + /** * * @author bsoorentino @@ -158,7 +146,7 @@ public boolean process( Context processingContext ) throws Exception { types.stream() .filter( t -> !t.isFunctionalInterface() ) .filter( t -> t.hasAlias() ) - .map( t -> TypescriptHelper.getAliasDeclaration(t.getValue(), t.getAlias()) ) + .map( t -> TypescriptConverter.getAliasDeclaration(t.getValue(), t.getAlias()) ) .forEach( wD_append ); types.addAll(PREDEFINED_TYPES); @@ -167,377 +155,25 @@ public boolean process( Context processingContext ) throws Exception { types.stream() .collect( Collectors.toMap( tt -> tt.getValue().getName() , tt -> tt )); + final TypescriptConverter converter = new TypescriptConverter(); + types.stream() .filter( tt -> !PREDEFINED_TYPES.contains(tt) ) - .map( tt -> processClass( 0, tt, declaredTypes)) + .map( tt -> converter.processClass( 0, tt, declaredTypes)) .forEach( wD_append ); wT.append( "/// " ).append( "\n\n"); types.stream() .filter( t -> t.isExport() ) - .map( t -> processStatic( t, declaredTypes)) + .map( t -> converter.processStatic( t, declaredTypes)) .forEach( wT_append ); } // end try-with-resources return true; } - /** - * - * @param m - * @param declaringType - * @param declaredTypeMap - * @return - */ - protected String getMethodParametersAndReturnDecl( E m, - TSType declaringType, - java.util.Map declaredTypeMap, - boolean packageResolution ) - { - final java.util.Set TypeVarSet = new java.util.HashSet<>(5); - - final Consumer> addTypeVar = tv -> TypeVarSet.add(tv.getName()) ; - - final Parameter[] params = m.getParameters(); - - final String params_string = - Arrays.stream(params) - .map( (tp) -> { - - final String name = getParameterName(tp); - - - if( tp.isVarArgs() ) { - - String type = null; - if( tp.getParameterizedType() instanceof GenericArrayType ) { - - type = convertJavaToTS( ((GenericArrayType)tp.getParameterizedType()).getGenericComponentType(), - m, - declaringType, - declaredTypeMap, - packageResolution, - Optional.of( addTypeVar )) ; - } - else { - type = convertJavaToTS( tp.getType().getComponentType(), - m, - declaringType, - declaredTypeMap, - packageResolution, - Optional.of( addTypeVar )) ; - } - return String.format( "...%s:%s[]", name, type ); - - } - - final String type = convertJavaToTS( tp.getParameterizedType(), - m, - declaringType, - declaredTypeMap, - packageResolution, - Optional.of( addTypeVar )) ; - return String.format( "%s:%s", name, type ); - }) - .collect(Collectors.joining(", ")) - ; - - final Type returnType = ( m instanceof Method ) ? - ((Method)m).getGenericReturnType() : - declaringType.getValue(); - - final String tsReturnType = - convertJavaToTS( returnType, - m, - declaringType, - declaredTypeMap, - packageResolution, - Optional.of( addTypeVar )); - - - final StringBuilder result = new StringBuilder(); - - if( !TypeVarSet.isEmpty() ) { - result - .append('<') - .append( TypeVarSet.stream().collect(Collectors.joining(","))) - .append('>'); - } - return result - .append("( ") - .append(params_string) - .append(" ):") - .append(tsReturnType) - .toString(); - } - - /** - * - * @param m - * @param declaringClass - * @param declaredClassMap - * @return - */ - private String getMethodDecl( final Method m, TSType declaringClass, java.util.Map declaredClassMap ) { - - final StringBuilder sb = new StringBuilder(); - - if( Modifier.isStatic(m.getModifiers()) ) { - - if( declaringClass.getValue().isInterface() ) { - sb.append( "// "); - } - - sb.append("static ").append(m.getName()); - - } - else { - - sb.append(m.getName()); - - } - - //if( m.getDeclaringClass().isInterface()) sb.append('?'); - sb.append( getMethodParametersAndReturnDecl(m, declaringClass, declaredClassMap, true) ); - - return sb.toString(); - - } - - /** - * - * @param type - * @return - */ - private Set getFields( final TSType type ) { - - final Predicate std = f -> - !f.isSynthetic() && - Modifier.isPublic( f.getModifiers() ) && - Character.isJavaIdentifierStart(f.getName().charAt(0)) && - f.getName().chars().skip(1).allMatch(Character::isJavaIdentifierPart); - - return Stream.concat( Stream.of(type.getValue().getFields()), Stream.of(type.getValue().getDeclaredFields()) ) - .filter(std) - .collect( Collectors.toSet( ) ); - - } - - /** - * - * @param type - * @return - */ - private Set getMethods( final TSType type) { - final Predicate include = m -> - !m.isBridge() && - !m.isSynthetic() && - Modifier.isPublic( m.getModifiers() ) && - Character.isJavaIdentifierStart(m.getName().charAt(0)) && - m.getName().chars().skip(1).allMatch(Character::isJavaIdentifierPart); - - return Stream.concat( Stream.of(type.getValue().getMethods()), Stream.of(type.getValue().getDeclaredMethods()) ) - .filter(include) - .collect( Collectors.toSet( ) ); - - } - - public static Predicate distinctByKey(Function keyExtractor) { - Map seen = new ConcurrentHashMap<>(); - return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null; - } - - /** - * - * @param sb - * @param type - * @param declaredTypeMap - */ - private void processNestedClasses( StringBuilder sb, int level, TSType tstype, java.util.Map declaredTypeMap ) { - - final Class nestedClasses[] = tstype.getValue().getClasses(); - - if( nestedClasses.length == 0 ) return; - - sb.append( "export module " ) - .append(tstype.getSimpleTypeName()) - .append(" {\n\n") - ; - - Stream.of(nestedClasses) - .filter( distinctByKey( c -> c.getSimpleName() ) ) - .map( cl -> TSType.from(cl) ) - .map( t -> processClass( level + 1, t, declaredTypeMap) ) - .forEach( decl -> sb.append(decl) ); - - sb.append("\n} // end module ") - .append(tstype.getSimpleTypeName()) - .append('\n') - ; - } - - - private StringBuilder processEnumDecl( StringBuilder sb, TSType type ) { - if( type.getValue().isEnum() ) { - type.setExport(true); // force export - Arrays.stream( type.getValue().getEnumConstants() ) - .forEach( (c) -> - sb.append( '\t' ) - .append( "// ") - .append( c.toString() ) - .append( ':') - .append( type.getSimpleTypeName() ) - .append( ';' ) - .append( '\n' ) - ); - sb.append('\n'); - } - - return sb; - - } - - private StringBuilder processEnumType( StringBuilder sb, TSType type ) { - if( type.getValue().isEnum() ) { - Arrays.stream( type.getValue().getEnumConstants() ) - .forEach( (c) -> - sb.append( '\t' ) - .append( c.toString() ) - .append( ':') - .append( type.getTypeName() ) - .append( ';' ) - .append( '\n' ) - ); - sb.append('\n'); - } - - return sb; - - } - - /** - * - * @param declaredClass - * @return - */ - private String processStatic( TSType type, java.util.Map declaredClassMap ) { - - final StringBuilder sb = new StringBuilder(); - - sb.append("interface ") - .append( type.getSimpleTypeName() ) - .append("Static {\n\n") - ; - processEnumType(sb, type) - //Append class property - .append("\treadonly class:any;\n"); - - Stream.of(type.getValue().getConstructors()) - .filter( c -> Modifier.isPublic(c.getModifiers()) ) - .forEach( c -> { - sb.append("\tnew") - .append( getMethodParametersAndReturnDecl( c, type, declaredClassMap, false) ) - .append(ENDL); - } - ); - - final java.util.Set methodSet = - getMethods( type ) - .stream() - .filter( TypescriptHelper::isStatic ) - .collect( Collectors.toCollection(() -> new java.util.LinkedHashSet<>() )); - - if( !methodSet.isEmpty() ) { - - methodSet.stream() - .sorted( (a,b) -> a.getName().compareTo(b.getName())) - .forEach( md -> - sb.append( '\t' ) - .append(md.getName()) - .append( getMethodParametersAndReturnDecl( md, type, declaredClassMap, false) ) - .append( ENDL )) - ; - } - - sb.append( "}\n\n" ) - .append("export const ") - .append(type.getSimpleTypeName()) - .append(": ") - .append(type.getSimpleTypeName()) - .append("Static = Java.type(\"") - .append( type.getValue().getName() ) - .append("\")") - .append( ENDL ) - .append("\n\n") - ; - - return sb.toString(); - } - - - /** - * - * @param bi - * @param declaredClassMap - * @return - */ - private String processClass( int level, TSType tstype, java.util.Map declaredClassMap ) { - - final StringBuilder sb = new StringBuilder(); - - final String namespace = tstype.getValue().getPackage().getName(); - - if( !tstype.getValue().isMemberClass() ) - sb.append( "declare namespace " ) - .append(namespace) - .append(" {\n\n") - ; - - getClassDecl( sb, tstype, declaredClassMap).append("\n\n"); - - processEnumDecl(sb, tstype); - - final java.util.Set methodSet = - getMethods( tstype ) - .stream() - .filter( md -> (tstype.isExport() && TypescriptHelper.isStatic(md))==false ) - .filter( (md) -> { - final String name = md.getName(); - return !( name.contains("$") || // remove unnamed - name.equals("getClass") || - name.equals("hashCode") || - name.equals("wait") || - name.equals("notify") || - name.equals("notifyAll") ); - }) - .collect( Collectors.toCollection(() -> new java.util.LinkedHashSet() )); - - methodSet.stream() - .map( md -> getMethodDecl(md, tstype, declaredClassMap) ) - .sorted().forEach( (decl) -> - sb.append( '\t' ) - .append(decl) - .append( ENDL )) - ; - - sb.append("\n} // end ") - .append(tstype.getSimpleTypeName()) - .append('\n'); - - // NESTED CLASSES - if( level == 0 ) processNestedClasses( sb, level, tstype, declaredClassMap); - - if( !tstype.getValue().isMemberClass() ) - sb.append("\n} // end namespace ") - .append( namespace ) - .append('\n'); - - return sb.toString(); - - } - - /** + /** * * @param entry * @return @@ -572,35 +208,9 @@ private java.util.Set enumerateDeclaredPackageAndClass( final Context pr .flatMap( entry -> this.getAnnotationValueValue(entry).stream() ) .map( av -> av.getValue() ) .filter( v -> v instanceof AnnotationMirror).map( v -> ((AnnotationMirror)v) ) - .map( am -> toMapObject(am, () -> new TSType() ) ) + .map( am -> toMapObject(am, () -> TSType.from( Void.class) ) ) .collect( Collectors.toSet() ) ; } - /** - * - * @param sb - * @param m - */ - @Deprecated - @SuppressWarnings("unused") - private StringBuilder appendStaticMethodTypeParameters( final StringBuilder sb, final Method m ) { - final TypeVariable[] return_type_parameters = m.getReturnType().getTypeParameters(); - - if( return_type_parameters.length > 0 ) { - - final String pp = - Arrays.asList( return_type_parameters ) - .stream() - .map( t -> t.getName() ) - .collect(Collectors.joining(",", "<", ">")) ; - - sb.append( pp ); - - } - - return sb; - } - - } diff --git a/processor/src/test/java/org/bsc/processor/ProcessorTest.java b/processor/src/test/java/org/bsc/processor/ProcessorTest.java index 6dac56f..4f7615e 100644 --- a/processor/src/test/java/org/bsc/processor/ProcessorTest.java +++ b/processor/src/test/java/org/bsc/processor/ProcessorTest.java @@ -12,6 +12,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.bsc.java2typescript.TSType; +import org.bsc.java2typescript.TypescriptConverter; import org.hamcrest.core.Is; import org.hamcrest.core.IsEqual; import org.hamcrest.core.IsNull; @@ -20,7 +22,7 @@ public class ProcessorTest { - final TypescriptProcessor processor = new TypescriptProcessor(); + final TypescriptConverter converter = new TypescriptConverter(); private java.util.Map declaredClassMap( Class ... classes) { return Stream.of( classes ) @@ -38,7 +40,7 @@ public void testWildcardType() throws Exception { final TSType type = TSType.from(Sample1.class); { final Method m = type.getValue().getMethod("merge", Sample2.class ); - final String result = processor.getMethodParametersAndReturnDecl( m, + final String result = converter.getMethodParametersAndReturnDecl( m, type, declaredTypeMap( TSType.from(String.class), TSType.from(Sample2.class)), true) ; @@ -48,7 +50,7 @@ public void testWildcardType() throws Exception { } { final Method m = type.getValue().getMethod("merge", BiConsumer.class ); - final String result = processor.getMethodParametersAndReturnDecl( m, + final String result = converter.getMethodParametersAndReturnDecl( m, type, declaredTypeMap( TSType.from(String.class), TSType.from(Sample2.class), TSType.from(BiConsumer.class)), true) ; @@ -58,7 +60,7 @@ public void testWildcardType() throws Exception { } { final Method m = type.getValue().getMethod("concatMap", Function.class ); - final String result = processor.getMethodParametersAndReturnDecl( m, + final String result = converter.getMethodParametersAndReturnDecl( m, type, declaredTypeMap( TSType.from(String.class), TSType.from(Sample2.class), TSType.functional(Function.class, "Func")), true) ; @@ -76,7 +78,7 @@ public void testFunctionalInterface() throws Exception { { final Method m = type.getValue().getMethod("transform", java.util.function.Function.class ); final Type pType = m.getGenericParameterTypes()[0]; - final String result = TypescriptHelper.convertJavaToTS(pType, m, + final String result = TypescriptConverter.convertJavaToTS(pType, m, type, declaredTypeMap( TSType.from(String.class), TSType.from(java.util.function.Function.class, "Func", false)), true, @@ -88,7 +90,7 @@ public void testFunctionalInterface() throws Exception { } { final Method m = type.getValue().getMethod("transform", java.util.function.Function.class ); - final String result = processor.getMethodParametersAndReturnDecl( m, + final String result = converter.getMethodParametersAndReturnDecl( m, type, declaredTypeMap( TSType.from(String.class), TSType.from(java.util.function.Function.class, "Func", false)), true) ; @@ -98,7 +100,7 @@ public void testFunctionalInterface() throws Exception { } { final Method m = type.getValue().getMethod("creator", java.util.concurrent.Callable.class ); - final String result = processor.getMethodParametersAndReturnDecl( m, + final String result = converter.getMethodParametersAndReturnDecl( m, type, declaredTypeMap( TSType.from(String.class), TSType.functional(java.util.concurrent.Callable.class, "Supplier")), true) ; @@ -114,7 +116,7 @@ public void testClassDecl() throws Exception { { final String result = - TypescriptHelper.getClassDecl( new StringBuilder(), TSType.from(ArrayList.class), Collections.emptyMap()).toString(); + converter.getClassDecl( TSType.from(ArrayList.class), Collections.emptyMap()); Assert.assertThat( result, IsNull.notNullValue()); Assert.assertThat( result, IsEqual.equalTo("class ArrayList/* extends AbstractList implements List, RandomAccess, java.lang.Cloneable, java.io.Serializable*/ {")); @@ -130,7 +132,7 @@ public void testAlias() throws Exception { { final Method m = type.getMethod("getAttributeList"); final Type rType = m.getGenericReturnType(); - final String result = TypescriptHelper.convertJavaToTS(rType, m, + final String result = TypescriptConverter.convertJavaToTS(rType, m, TSType.from(type), declaredTypeMap( TSType.from(String.class), TSType.from(java.util.List.class, "List", true) ), true, @@ -141,7 +143,7 @@ public void testAlias() throws Exception { { final Method m = type.getMethod("getAttributeList", java.util.List.class); - final String result = processor.getMethodParametersAndReturnDecl( m, + final String result = converter.getMethodParametersAndReturnDecl( m, TSType.from(type), declaredTypeMap( TSType.from(String.class), TSType.from(java.util.List.class, "List", true) ), true) ; @@ -166,7 +168,7 @@ public void testSample1() throws Exception { { final Method m = type.getMethod("method4"); final Type rType = m.getGenericReturnType(); - final String result = TypescriptHelper.convertJavaToTS(rType, m, + final String result = TypescriptConverter.convertJavaToTS(rType, m, TSType.from(type), Collections.emptyMap(), true, @@ -177,7 +179,7 @@ public void testSample1() throws Exception { { final Method m = type.getMethod("method5"); final Type rType = m.getGenericReturnType(); - final String result = TypescriptHelper.convertJavaToTS(rType, m, + final String result = TypescriptConverter.convertJavaToTS(rType, m, TSType.from(type), Collections.emptyMap(), true, @@ -188,7 +190,7 @@ public void testSample1() throws Exception { { final Method m = type.getMethod("method1_1"); final Type rType = m.getGenericReturnType(); - final String result = TypescriptHelper.convertJavaToTS(rType, m, + final String result = TypescriptConverter.convertJavaToTS(rType, m, TSType.from(type), declaredClassMap(Sample2.class), true, @@ -199,7 +201,7 @@ public void testSample1() throws Exception { { final Method m = type.getMethod("method1_2"); final Type rType = m.getGenericReturnType(); - final String result = TypescriptHelper.convertJavaToTS(rType, m, + final String result = TypescriptConverter.convertJavaToTS(rType, m, TSType.from(type), declaredClassMap(Sample2.class,java.lang.Comparable.class), true, @@ -211,7 +213,7 @@ public void testSample1() throws Exception { TypeVarSet.clear(); final Method m = type.getMethod("method1_3"); final Type rType = m.getGenericReturnType(); - final String result = TypescriptHelper.convertJavaToTS(rType, m, + final String result = TypescriptConverter.convertJavaToTS(rType, m, TSType.from(type), declaredClassMap(java.util.function.BiPredicate.class), true, @@ -225,7 +227,7 @@ public void testSample1() throws Exception { { final Method m = type.getMethod("method1_3"); final Type rType = m.getGenericReturnType(); - final String result = TypescriptHelper.convertJavaToTS(rType, m, + final String result = TypescriptConverter.convertJavaToTS(rType, m, TSType.from(type), Collections.emptyMap(), true, @@ -236,7 +238,7 @@ public void testSample1() throws Exception { { final Method m = type.getMethod("method1"); final Type rType = m.getGenericReturnType(); - final String result = TypescriptHelper.convertJavaToTS(rType, m, + final String result = TypescriptConverter.convertJavaToTS(rType, m, TSType.from(type), declaredClassMap(java.util.Map.class), true, @@ -248,7 +250,7 @@ public void testSample1() throws Exception { { final Method m = type.getMethod("method2", Sample2.class); final Type rType = m.getGenericReturnType(); - final String result = TypescriptHelper.convertJavaToTS(rType, m, + final String result = TypescriptConverter.convertJavaToTS(rType, m, TSType.from(type), Collections.emptyMap(), true, @@ -257,7 +259,7 @@ public void testSample1() throws Exception { Assert.assertThat( result, IsEqual.equalTo("string")); final Type pType = m.getParameters()[0].getParameterizedType(); - final String rresult = TypescriptHelper.convertJavaToTS(pType, m, + final String rresult = TypescriptConverter.convertJavaToTS(pType, m, TSType.from(type), declaredClassMap(Sample2.class), true, @@ -269,7 +271,7 @@ public void testSample1() throws Exception { { final Method m = type.getMethod("method2_1", Sample2.class); final Type rType = m.getGenericReturnType(); - final String result = TypescriptHelper.convertJavaToTS(rType, m, + final String result = TypescriptConverter.convertJavaToTS(rType, m, TSType.from(type), declaredClassMap(Sample2.class, CharSequence.class), true, @@ -278,7 +280,7 @@ public void testSample1() throws Exception { Assert.assertThat( result, IsEqual.equalTo("string")); final Type pType = m.getParameters()[0].getParameterizedType(); - final String rresult = TypescriptHelper.convertJavaToTS(pType, m, + final String rresult = TypescriptConverter.convertJavaToTS(pType, m, TSType.from(type), declaredClassMap(Sample2.class), true, @@ -298,7 +300,7 @@ public void testSample1() throws Exception { Assert.assertThat( result, IsEqual.equalTo("string")); final Type pType = m.getParameters()[0].getParameterizedType(); - final String rresult = TypescriptHelper.convertJavaToTS(pType, m, + final String rresult = TypescriptConverter.convertJavaToTS(pType, m, TSType.from(type), declaredClassMap(Sample2.class, Consumer.class), true, @@ -321,7 +323,7 @@ public void testSample1() throws Exception { final String[] arr = {}; final Method m = type.getMethod("method6", arr.getClass()); - final String result = processor.getMethodParametersAndReturnDecl( m, TSType.from(type), Collections.emptyMap(), true) ; + final String result = converter.getMethodParametersAndReturnDecl( m, TSType.from(type), Collections.emptyMap(), true) ; Assert.assertThat( result, IsNull.notNullValue()); Assert.assertThat( result, IsEqual.equalTo("( ...args:string[] ):void")); @@ -352,7 +354,7 @@ String getReturnType( java.util.Map declaredClassMap, Class t String getReturnType( java.util.Map declaredClassMap, Class type, Method m ) throws Exception { final Type rType = m.getGenericReturnType(); - final String result = TypescriptHelper.convertJavaToTS(rType, m, + final String result = TypescriptConverter.convertJavaToTS(rType, m, TSType.from(type), declaredClassMap, true,