Skip to content

Commit

Permalink
Merge branch 'feature/types' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
bsorrentino committed Dec 29, 2017
2 parents 12d424e + 8e2edd2 commit 01b44c4
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 68 deletions.
2 changes: 1 addition & 1 deletion jdk8/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
<configuration>
<outputDirectory>${project.build.directory}</outputDirectory>
<options>
<ts.outfile>jdk8.d.ts</ts.outfile>
<ts.outfile>jdk8</ts.outfile>
</options>
</configuration>
</execution>
Expand Down
41 changes: 41 additions & 0 deletions jdk8/src/main/java/org/bsc/java2ts/jdk8/package-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
@Java2TS(declare = {
@Type(java.lang.Class.class),
@Type(java.lang.Iterable.class),
@Type(java.lang.CharSequence.class),
@Type(value=java.lang.String.class, export=true),
@Type(java.lang.Comparable.class),
@Type(java.lang.Runnable.class),

@Type(java.util.stream.BaseStream.class),
@Type(value=java.util.stream.Stream.class, export=true),

@Type(java.util.Iterator.class),
@Type(java.util.Comparator.class),
@Type(java.util.Collection.class),
@Type(java.util.Map.class),
@Type(java.util.List.class ),
@Type(java.util.Set.class),
@Type(value=java.util.HashMap.class, export=true),
@Type(value=java.util.HashSet.class, export=true),
@Type(value=java.util.ArrayList.class, export=true),
@Type(value=java.util.Optional.class, export=true),

@Type(value=java.nio.file.Files.class, export=true),
@Type(java.nio.file.Path.class),
@Type(value=java.nio.file.Paths.class, export=true),
@Type(java.nio.file.AccessMode.class),

@Type(java.util.function.UnaryOperator.class),
@Type(java.util.function.Consumer.class),
@Type(java.util.function.Predicate.class)

})
package org.bsc.java2ts.jdk8;

import org.bsc.processor.annotation.Java2TS;
import org.bsc.processor.annotation.Type;
40 changes: 0 additions & 40 deletions jdk8/src/main/java/org/test/package-info.java

This file was deleted.

8 changes: 7 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,13 @@
<groupId>com.github.spullara.mustache.java</groupId>
<artifactId>compiler</artifactId>
<version>0.9.4</version>
</dependency>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1.2</version>
</dependency>

</dependencies>
</dependencyManagement>
</project>
5 changes: 5 additions & 0 deletions processor/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,10 @@
<artifactId>metainf-services</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
</dependency>

</dependencies>
</project>
177 changes: 152 additions & 25 deletions processor/src/main/java/org/bsc/processor/TypescriptProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,29 @@
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.RandomAccess;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedOptions;
import javax.annotation.processing.SupportedSourceVersion;
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.type.DeclaredType;
import javax.tools.FileObject;

/**
Expand Down Expand Up @@ -78,6 +83,31 @@ public class TypescriptProcessor extends AbstractProcessorEx {
java.util.Optional.class
);

/**
*
* @param w
* @param t
*/
private void addDeclaration( java.io.Writer w, TSType t, boolean isRhinoCompatible ) {
if( !t.isExport() ) return;

Class<?> type = t.valueAsClass();

info( "export type [%s]", t.getValue() );

try {
if( isRhinoCompatible ) {
w.append( String.format( "exports.%s\t\t=\t%s;\n", type.getSimpleName(), type.getName()));
}
else {
w.append( String.format( "exports.%s\t\t=\tJava.type( \"%s\" );\n", type.getSimpleName(), type.getName()));
}
} catch (IOException e) {
error( "error adding [%s]", t.getValue());
}

}

/**
*
* @param processingContext
Expand All @@ -86,21 +116,33 @@ public class TypescriptProcessor extends AbstractProcessorEx {
@Override
public boolean process( Context processingContext ) throws Exception {

final String targetFile = processingContext.getOptionMap().getOrDefault("ts.outfile", "out.d.ts");
final String targetDefinitionFile = processingContext.getOptionMap().getOrDefault("ts.outfile", "out");
final String compatibility = processingContext.getOptionMap().getOrDefault("compatibility", "nashorn");


final FileObject out = super.getSourceOutputFile( Paths.get("ts"), Paths.get(targetFile));
final FileObject outD = super.getSourceOutputFile( Paths.get("ts"), Paths.get(targetDefinitionFile.concat(".d.ts")));
final FileObject outT = super.getSourceOutputFile( Paths.get("ts"), Paths.get(targetDefinitionFile.concat(".ts")));

info( "output [%s]", out.getName() );
info( "output definition file [%s]", outD.getName() );
info( "output declaration file [%s]", outT.getName() );

final java.io.Writer w = out.openWriter();
final java.io.Writer wD = outD.openWriter();
final java.io.Writer wT = outT.openWriter();

try(final java.io.InputStream is = getClass().getClassLoader().getResourceAsStream("header.ts") ) {
int c;
while( (c = is.read()) != -1 ) w.write(c);
while( (c = is.read()) != -1 ) wD.write(c);
}

final List<Class<?>> classes = enumerateDeclaredPackageAndClass( processingContext );
final List<TSType> types = enumerateDeclaredPackageAndClass( processingContext );


final List<Class<?>> classes = types.stream()
.peek( t -> addDeclaration(wT, t, compatibility.equalsIgnoreCase("rhino")) )
.map( t -> t.valueAsClass() )
.collect( Collectors.toList());


//
// Check for Required classes
//
Expand All @@ -118,13 +160,14 @@ public boolean process( Context processingContext ) throws Exception {
.map( clazz -> processClass( getBeanInfo(clazz), declaredClasses))
.forEach( s -> {
try {
w.append( s );
wD.append( s );
} catch (IOException e) {
error( "error adding [%s]", s);
}
} );

w.close();
wD.close();
wT.close();

return true;
}
Expand Down Expand Up @@ -440,7 +483,7 @@ private String processClass( BeanInfo bi, java.util.Map<String, Class<?>> decla
* @param dt
* @return
*/
private Class<?> getClassFrom( DeclaredType dt ) {
private Class<?> getClassFrom( Object dt ) {
try {
return Class.forName(dt.toString());
} catch (ClassNotFoundException e1) {
Expand All @@ -463,27 +506,111 @@ private List<? extends AnnotationValue> getAnnotationValueValue(
return (List<? extends AnnotationValue>)av.getValue();

}

/**
*
* @param am
* @param finisher
* @return
*/
protected <R> R toMapObject( AnnotationMirror am, java.util.function.Function<Map<String,Object>, R> finisher ) {

final Collector<Map.Entry<? extends ExecutableElement, ? extends AnnotationValue>, Map<String,Object>, R> c =
Collector.of(
() -> new java.util.HashMap<String,Object>(),
( map, entry ) ->
map.put( entry.getKey().getSimpleName().toString(), entry.getValue().getValue()),
( v1, v2 ) -> v1,
finisher );

final R result = am.getElementValues()
.entrySet()
.stream()
.collect( c );

return result;

}

/**
*
* toJsonObject( am, ( builder ) -> builder.build() );
*
*
* @param am
* @param finisher
* @return
*/
protected <R> R toJsonObject( AnnotationMirror am, java.util.function.Function<JsonObjectBuilder, R> finisher ) {

final Collector<Map.Entry<? extends ExecutableElement, ? extends AnnotationValue>, JsonObjectBuilder, R> c =
Collector.of(
() -> Json.createObjectBuilder(),
( builder, entry ) -> {
final String k = entry.getKey().getSimpleName().toString();
final Object v = entry.getValue().getValue();

if( v == null ) builder.addNull(k);
else if( v instanceof Boolean ) builder.add(k, (Boolean)v );
else builder.add(k, String.valueOf(v));

},
( v1, v2 ) -> v1,
finisher );

final R result = am.getElementValues()
.entrySet()
.stream()
.collect( c );

return result;

}

class TSType {
final JsonObject internal;

public TSType(JsonObject internal) {
super();
this.internal = internal;
}

public String getValue() {
return internal.getString("value");
}

public Class<?> valueAsClass() {
return getClassFrom(internal.getString("value"));
}

public boolean isExport() {
return internal.getBoolean("export", false);
}

}

/**
*
* @param processingContext
* @return
*/
private java.util.List<Class<?>> enumerateDeclaredPackageAndClass( final Context processingContext ) {

return processingContext.elementFromAnnotations( Optional.empty() ).stream()
.peek((e) -> info( "Anotation [%s]", e.getKind().name()) )
.filter( (e) -> ElementKind.PACKAGE==e.getKind() || ElementKind.CLASS==e.getKind() )
.flatMap( (e) -> e.getAnnotationMirrors().stream() )
.peek((m) -> info( "Mirror [%s]", m.toString() ))
.flatMap( am -> am.getElementValues().entrySet().stream() )
.filter( entry -> "declare".equals(String.valueOf(entry.getKey().getSimpleName())) )
.flatMap( entry -> this.getAnnotationValueValue(entry).stream() )
.map( (av) -> av.getValue() )
.filter( v -> v instanceof DeclaredType )
.map( v -> (DeclaredType)v )
.map(this::getClassFrom )
.collect( Collectors.toList())
private java.util.List<TSType> enumerateDeclaredPackageAndClass( final Context processingContext ) {

return
processingContext.elementFromAnnotations( Optional.empty() ).stream()
.peek( e -> info( "Anotation [%s]", e.getKind().name()) )
.filter( e -> ElementKind.PACKAGE==e.getKind() || ElementKind.CLASS==e.getKind() )
.flatMap( e -> e.getAnnotationMirrors().stream() )
.peek( m -> info( "Mirror [%s]", m.toString() ))
.flatMap( am -> am.getElementValues()
.entrySet()
.stream()
.filter( entry -> "declare".equals(String.valueOf(entry.getKey().getSimpleName())) ))
.flatMap( entry -> this.getAnnotationValueValue(entry).stream() )
.map( av -> av.getValue() )
.filter( v -> v instanceof AnnotationMirror).map( v -> ((AnnotationMirror)v) )
.map( am -> toJsonObject(am, (builder) -> { return new TSType( builder.build() ); } ) )
.collect( Collectors.toList() )
;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@
@Target( {ElementType.TYPE, ElementType.PACKAGE} )
public @interface Java2TS {

Class<?>[] declare() default {};
Type[] declare() default {};
}
13 changes: 13 additions & 0 deletions processor/src/main/java/org/bsc/processor/annotation/Type.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.bsc.processor.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.SOURCE)
@Target( {ElementType.ANNOTATION_TYPE} )
public @interface Type {
Class<?> value();
boolean export() default false ;
}

0 comments on commit 01b44c4

Please sign in to comment.