diff --git a/.gitignore b/.gitignore index ae53bbb..63ac1f2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ target/ .classpath .settings/ .project +.vscode/ diff --git a/core/src/main/java/org/bsc/java2typescript/TSType.java b/core/src/main/java/org/bsc/java2typescript/TSType.java index e503b50..381c692 100644 --- a/core/src/main/java/org/bsc/java2typescript/TSType.java +++ b/core/src/main/java/org/bsc/java2typescript/TSType.java @@ -95,12 +95,18 @@ public String getAlias() { return (String) super.get(ALIAS); } + private String getMemberSimpleTypeName() { + + return format( "%s$%s", getValue().getDeclaringClass().getSimpleName(), getValue().getSimpleName()); + } + /** * * @return */ public final String getTypeName() { - return (hasAlias()) ? getAlias() : format( "%s.%s", getNamespace(), getValue().getSimpleName()); + return (hasAlias()) ? getAlias() : format( "%s.%s", getNamespace(), + (getValue().isMemberClass() ? getMemberSimpleTypeName() : getValue().getSimpleName())); } /** @@ -108,7 +114,8 @@ public final String getTypeName() { * @return */ public final String getSimpleTypeName() { - return (hasAlias()) ? getAlias() : getValue().getSimpleName(); + return (hasAlias()) ? getAlias() : + ((getValue().isMemberClass()) ? getMemberSimpleTypeName() : getValue().getSimpleName()); } /** @@ -116,7 +123,7 @@ public final String getSimpleTypeName() { * @return */ public final boolean supportNamespace() { - return !getValue().isMemberClass() && !hasAlias(); + return !hasAlias(); } /** @@ -165,6 +172,19 @@ public Set getMethods() { } + /** + * + * @param name + * @return + */ + private Class getMemberClassForName( String fqn ) throws ClassNotFoundException { + char[] ch = fqn.toCharArray(); + int i = fqn.lastIndexOf('.'); + ch[i] = '$'; + + return Class.forName(String.valueOf(ch)); + } + /** * * @param dt @@ -174,10 +194,18 @@ private Class getClassFrom(Object dt) { if (dt instanceof Class) return (Class) dt; + final String fqn = dt.toString(); try { - return Class.forName(dt.toString()); + return Class.forName(fqn); + } catch (ClassNotFoundException e1) { - throw new RuntimeException(String.format("class not found [%s]", dt), e1); + + try { + return getMemberClassForName(fqn); + + } catch (ClassNotFoundException e2) { + throw new RuntimeException(String.format("class not found [%s]", dt), e1); + } } } diff --git a/core/src/main/java/org/bsc/java2typescript/TypescriptConverter.java b/core/src/main/java/org/bsc/java2typescript/TypescriptConverter.java index 44e5a12..016f2e5 100644 --- a/core/src/main/java/org/bsc/java2typescript/TypescriptConverter.java +++ b/core/src/main/java/org/bsc/java2typescript/TypescriptConverter.java @@ -63,13 +63,13 @@ public class TypescriptConverter { false ; - private final static void log( String fmt, Object ...args ) { - //System.out.println( format( fmt, (Object[])args)); + protected final static void log( String fmt, Object ...args ) { + if( Boolean.getBoolean("debug") ) System.out.println( format( fmt, args)); } - private final static void debug( String fmt, Object ...args ) { + protected final static void debug( String fmt, Object ...args ) { System.out.print( "DEBUG: "); - System.out.println( format( fmt, (Object[])args)); + System.out.println( format( fmt, args)); } @@ -224,14 +224,27 @@ public static String convertJavaToTS( Type type, return format("any /*%s*/",rawType.getName()); } - String result = pType.getTypeName() - .replace( rawType.getName(), tstype.getTypeName()) // use Alias - ; + log( "ParameterizedType\n\t[%s]\n\traw[%s]\n\ttstype[%s]", + pType.getTypeName(), + rawType.getName(), + tstype.getTypeName() ); + + String result = pType.getTypeName(); + if( rawType.isMemberClass() ) { + result = result + .replace( rawType.getDeclaringClass().getName().concat("."), "" ) // use Alias + ; + } + + result = result.replace( rawType.getName(), tstype.getTypeName()) // use Alias + ; if( packageResolution && isNamespaceMatch.test(tstype, declaringType) ) { result = result.replace( tstype.getTypeName(), tstype.getSimpleTypeName()); } + + final Type[] typeArgs = pType.getActualTypeArguments(); for( Type t : typeArgs ) { @@ -243,7 +256,7 @@ public static String convertJavaToTS( Type type, declaredTypeMap, packageResolution, onTypeMismatch); - log( "Parameterized Type %s - %s", t, typeName ); + log( "Parameterized Type %s - %s", t.getTypeName(), typeName ); result = result.replace( t.getTypeName(), typeName); } @@ -655,208 +668,182 @@ private String getMethodDecl( Context ctx, final Method m, boolean optional ) { 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(); - + 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 ) { + Context append(CharSequence cs) { sb.append(cs); return this; } - + /** * * @param ch * @return */ - Context append( char ch ) { + 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 */" ); - - if( type.hasAlias()) sb.append("declare "); - - 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 || type.hasAlias()) { - - sb.append("/*"); - - if( type.hasAlias() ) sb.append( type.getValue().getName() ); - if( inherited.length()>0 ) sb.append( inherited ); - - sb.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(); - } - + * + * @return + */ + Context getClassDecl() { + + final StringBuilder inherited = new StringBuilder(); + + if (type.getValue().isInterface()) { + sb.append("interface "); + } else { + + if (type.getValue().isEnum()) + sb.append("/* enum */"); + + if (type.hasAlias()) + sb.append("declare "); + + 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 || type.hasAlias()) { + + sb.append("/*"); + + if (type.hasAlias()) + sb.append(type.getValue().getName()); + if (inherited.length() > 0) + sb.append(inherited); + + sb.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 processMemberClasses(int level) { + + final Class memberClasses[] = type.getValue().getClasses(); + + if (memberClasses.length == 0) + return this; + + // sb.append( "export module " ) + // .append(type.getSimpleTypeName()) + // .append(" {\n\n") + // ; + + Stream.of(memberClasses) + .peek( c -> debug("nested class name[%s]", c.getName()) ) + //.filter(distinctByKey( c -> c.getSimpleName() )) + .filter(distinctByKey(c -> c.getName())) + .map(cl -> TSType.from(cl)) + .peek( t -> debug("nested type name[%s]", t.getTypeName()) ) + .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(); + } - } - + } // end Context + /** + * + * @param tstype + * @param declaredTypeMap + * @return + */ + public Context contextOf( TSType tstype, java.util.Map declaredTypeMap ) { + return new Context( tstype, declaredTypeMap); + } + /** * * @param bi @@ -865,7 +852,7 @@ public String toString() { */ public String processClass( int level, TSType tstype, java.util.Map declaredTypeMap ) { - final Context ctx = new Context( tstype, declaredTypeMap); + final Context ctx = contextOf( tstype, declaredTypeMap); if( tstype.supportNamespace() ) ctx.append( "declare namespace " ) @@ -928,7 +915,7 @@ public String processClass( int level, TSType tstype, java.util.Map declaredClassMap( Class ... classes) { + return Stream.of( classes ) + .collect( Collectors.toMap( c -> c.getName(), c -> TSType.from(c) )) + ; + } + protected java.util.Map declaredTypeMap( TSType ... types) { + return Stream.of( types ) + .collect( Collectors.toMap( t -> t.getValue().getName(), t -> t )) + ; + } + + protected String getReturnType( Class type, String methonName, Class ...args ) throws Exception { + return getReturnType(Collections.emptyMap(), type, methonName, (Class[])args); + } + + protected String getReturnType( java.util.Map declaredClassMap, Class type, String methodName, Class ...args ) throws Exception + { + final Method m = type.getMethod(methodName, (Class[])args); + return getReturnType( declaredClassMap, type, m); + } + + protected String getReturnType( java.util.Map declaredClassMap, Class type, Method m ) throws Exception + { + final Type rType = m.getGenericReturnType(); + final String result = TypescriptConverter.convertJavaToTS(rType, m, + TSType.from(type), + declaredClassMap, + true, + Optional.empty()); + return result; + } + +} diff --git a/core/src/test/java/org/bsc/java2typescript/ConverterTest.java b/core/src/test/java/org/bsc/java2typescript/ConverterTest.java index 29eaf02..cc07d67 100644 --- a/core/src/test/java/org/bsc/java2typescript/ConverterTest.java +++ b/core/src/test/java/org/bsc/java2typescript/ConverterTest.java @@ -1,14 +1,15 @@ package org.bsc.java2typescript; -import java.util.function.Consumer; -import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; + +import java.util.function.Consumer; + import org.junit.Assert; import org.junit.Test; -public class ConverterTest { +public class ConverterTest extends AbstractConverterTest { interface Action { @@ -26,10 +27,11 @@ interface Action2 { public void functionalInterfaceTest() { - Assert.assertThat(TypescriptConverter.isFunctionalInterface(java.lang.Runnable.class) , is(true)); - Assert.assertThat(TypescriptConverter.isFunctionalInterface(Consumer.class) , is(true)); - Assert.assertThat(TypescriptConverter.isFunctionalInterface(Action.class) , is(true)); - Assert.assertThat(TypescriptConverter.isFunctionalInterface(Action.class), is(true)); - Assert.assertThat(TypescriptConverter.isFunctionalInterface(Action2.class) , is(false)); + Assert.assertThat(TypescriptConverter.isFunctionalInterface(java.lang.Runnable.class) , equalTo(true)); + Assert.assertThat(TypescriptConverter.isFunctionalInterface(Consumer.class) , equalTo(true)); + Assert.assertThat(TypescriptConverter.isFunctionalInterface(Action.class) , equalTo(true)); + Assert.assertThat(TypescriptConverter.isFunctionalInterface(Action.class), equalTo(true)); + Assert.assertThat(TypescriptConverter.isFunctionalInterface(Action2.class) , equalTo(false)); } + } diff --git a/core/src/test/java/org/bsc/java2typescript/MemeberClassTest.java b/core/src/test/java/org/bsc/java2typescript/MemeberClassTest.java new file mode 100644 index 0000000..c79a6bb --- /dev/null +++ b/core/src/test/java/org/bsc/java2typescript/MemeberClassTest.java @@ -0,0 +1,59 @@ +package org.bsc.java2typescript; + +import static org.hamcrest.core.IsEqual.equalTo; + +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.Optional; + +import org.hamcrest.core.IsNull; +import org.junit.Assert; +import org.junit.Test; + +public class MemeberClassTest extends AbstractConverterTest { + + + @Test + public void testMemberClassInfos() { + + final TSType type = TSType.from( java.util.Map.Entry.class ); + + Assert.assertThat(type.supportNamespace() , equalTo(true)); + Assert.assertThat(type.getNamespace() , equalTo("java.util")); + + Assert.assertThat(type.getTypeName() , equalTo("java.util.Map$Entry")); + Assert.assertThat(type.getSimpleTypeName() , equalTo("Map$Entry")); + } + + @Test + public void testMemberClass() throws Exception { + + TypescriptConverter.Context ctx = converter.contextOf(TSType.from( java.util.Map.Entry.class ), declaredTypeMap()); + + Assert.assertThat(ctx, IsNull.notNullValue()); + + final String result = ctx.getClassDecl().toString(); + + Assert.assertThat( result, IsNull.notNullValue()); + Assert.assertThat( result, equalTo("interface Map$Entry {")); + + } + + @Test + public void testMemberClassUsage() throws Exception { + + final Class type = java.util.Map.class; + + final Method m = type.getMethod("entrySet"); + final Type rType = m.getGenericReturnType(); + + final String result = TypescriptConverter.convertJavaToTS(rType, m, + TSType.from(type), + declaredTypeMap( TSType.from(java.util.Set.class), TSType.from(java.util.Map.Entry.class)), + true, + Optional.empty()); + + Assert.assertThat( result, equalTo("Set>")); + } + +} diff --git a/core/src/test/java/org/bsc/java2typescript/ProcessorTest.java b/core/src/test/java/org/bsc/java2typescript/ProcessorTest.java index 111b2c6..d94e88b 100644 --- a/core/src/test/java/org/bsc/java2typescript/ProcessorTest.java +++ b/core/src/test/java/org/bsc/java2typescript/ProcessorTest.java @@ -9,32 +9,16 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; -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; import org.junit.Assert; import org.junit.Test; -public class ProcessorTest { +public class ProcessorTest extends AbstractConverterTest { - final TypescriptConverter converter = new TypescriptConverter(); - - private java.util.Map declaredClassMap( Class ... classes) { - return Stream.of( classes ) - .collect( Collectors.toMap( c -> c.getName(), c -> TSType.from(c) )) - ; - } - private java.util.Map declaredTypeMap( TSType ... types) { - return Stream.of( types ) - .collect( Collectors.toMap( t -> t.getValue().getName(), t -> t )) - ; - } - @Test public void testWildcardType() throws Exception { final TSType type = TSType.from(Sample1.class); @@ -114,9 +98,9 @@ public void testFunctionalInterface() throws Exception { @Test public void testClassDecl() throws Exception { + TypescriptConverter.Context ctx = converter.contextOf(TSType.from(ArrayList.class), Collections.emptyMap()); { - final String result = - converter.getClassDecl( TSType.from(ArrayList.class), Collections.emptyMap()); + final String result = ctx.getClassDecl().toString(); Assert.assertThat( result, IsNull.notNullValue()); Assert.assertThat( result, IsEqual.equalTo("class ArrayList/* extends AbstractList implements List, RandomAccess, java.lang.Cloneable, java.io.Serializable*/ {")); @@ -341,24 +325,4 @@ public void testSample1() throws Exception { } - String getReturnType( Class type, String methonName, Class ...args ) throws Exception { - return getReturnType(Collections.emptyMap(), type, methonName, (Class[])args); - } - - String getReturnType( java.util.Map declaredClassMap, Class type, String methodName, Class ...args ) throws Exception - { - final Method m = type.getMethod(methodName, (Class[])args); - return getReturnType( declaredClassMap, type, m); - } - - String getReturnType( java.util.Map declaredClassMap, Class type, Method m ) throws Exception - { - final Type rType = m.getGenericReturnType(); - final String result = TypescriptConverter.convertJavaToTS(rType, m, - TSType.from(type), - declaredClassMap, - true, - Optional.empty()); - return result; - } } diff --git a/sample/src/main/java/org/bsc/java2ts/jdk8/package-info.java b/sample/src/main/java/org/bsc/java2ts/jdk8/package-info.java index 291606e..f5b0886 100644 --- a/sample/src/main/java/org/bsc/java2ts/jdk8/package-info.java +++ b/sample/src/main/java/org/bsc/java2ts/jdk8/package-info.java @@ -3,25 +3,30 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -@Java2TS(declare = { +@Java2TS(declare = { @Type(java.lang.System.class), - - @Type(value=java.util.List.class), + + @Type(value=java.util.List.class), @Type(value=java.util.Arrays.class, export=true), - @Type(java.nio.file.Files.class), - @Type(java.nio.file.Path.class), + @Type(java.nio.file.Files.class), + @Type(java.nio.file.Path.class), @Type(java.nio.file.Paths.class), @Type(java.nio.file.AccessMode.class), - + @Type(value=java.net.URI.class, export=true), @Type(java.net.URL.class), @Type(value=java.util.concurrent.Callable.class, alias="Callable"), - - + // Member Classes + @Type(value=java.util.Map.Entry.class), + //@Type(value= javax.swing.text.AbstractDocument.class), + //@Type(value= javax.swing.text.AbstractDocument.AttributeContext.class), + + + }) package org.bsc.java2ts.jdk8;