Add post-processing SPI for modifying generated types
We have the need internally to modify generated Thrift classes. This is currently done ad-hoc with a combination of Python and sed scripting, but we can and should be more rigorous. This commit introduces `TypeProcessor` as an SPI, implementations of which can be provided on the command line. Implementations will receive a JavaPoet `TypeSpec` for every generated class, before that type is written, and must return a `TypeSpec`. The returned type will be what is written to disk. The returned `TypeSpec` will typically be augmented in some way - a new interface implementation, or additional methods, or anything else one might wish.
This commit is contained in:
Родитель
8df3c57d7f
Коммит
9a3c9be424
|
@ -4,3 +4,6 @@ include 'thrifty-runtime'
|
||||||
include 'thrifty-java-codegen'
|
include 'thrifty-java-codegen'
|
||||||
include 'thrifty-gradle-plugin'
|
include 'thrifty-gradle-plugin'
|
||||||
include 'thrifty-compiler'
|
include 'thrifty-compiler'
|
||||||
|
include 'thrifty-example-postprocessor'
|
||||||
|
include 'thrifty-compiler-plugins'
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
dependencies {
|
||||||
|
compile libraries.javaPoet
|
||||||
|
testCompile group: 'junit', name: 'junit', version: '4.11'
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package com.bendb.thrifty.compiler;
|
||||||
|
|
||||||
|
import com.bendb.thrifty.compiler.spi.TypeProcessor;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.ServiceLoader;
|
||||||
|
|
||||||
|
public final class TypeProcessorService {
|
||||||
|
private static TypeProcessorService instance;
|
||||||
|
|
||||||
|
public static synchronized TypeProcessorService getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new TypeProcessorService();
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServiceLoader<TypeProcessor> serviceLoader = ServiceLoader.load(TypeProcessor.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the first {@link TypeProcessor} implementation loaded, or
|
||||||
|
* {@code null} if none are found.
|
||||||
|
*
|
||||||
|
* Because service ordering is non-deterministic, only the first instance
|
||||||
|
* is returned. A warning will be printed if more than one are found.
|
||||||
|
*
|
||||||
|
* @return The first located {@link TypeProcessor}, or {@code null}.
|
||||||
|
*/
|
||||||
|
public TypeProcessor get() {
|
||||||
|
TypeProcessor processor = null;
|
||||||
|
|
||||||
|
Iterator<TypeProcessor> iter = serviceLoader.iterator();
|
||||||
|
if (iter.hasNext()) {
|
||||||
|
processor = iter.next();
|
||||||
|
|
||||||
|
if (iter.hasNext()) {
|
||||||
|
System.err.println("Multiple TypeProcessors found; using "
|
||||||
|
+ processor.getClass().getTypeName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return processor;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package com.bendb.thrifty.compiler.spi;
|
||||||
|
|
||||||
|
import com.squareup.javapoet.TypeSpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When specified as part of code generation, processes all types after they
|
||||||
|
* are computed, but before they are written to disk. This allows you to make
|
||||||
|
* arbitrary modifications to types such as implementing your own interfaces,
|
||||||
|
* renaming fields, or anything you might wish to do.
|
||||||
|
*
|
||||||
|
* <p>For example, a processor that implements java.lang.Serializable on all
|
||||||
|
* generated types:
|
||||||
|
*
|
||||||
|
* <pre><code>
|
||||||
|
* public class SerializableTypeProcessor implements TypeProcessor {
|
||||||
|
* {@literal @}Override
|
||||||
|
* public TypeSpec process(TypeSpec type) {
|
||||||
|
* TypeSpec builder = type.toBuilder();
|
||||||
|
*
|
||||||
|
* builder.addSuperinterface(Serializable.class);
|
||||||
|
* builder.addField(FieldSpec.builder(long.class, "serialVersionUID")
|
||||||
|
* .addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
|
||||||
|
* .initializer("$L", -1)
|
||||||
|
* .build());
|
||||||
|
*
|
||||||
|
* return builder.build();
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </code></pre>
|
||||||
|
*/
|
||||||
|
public interface TypeProcessor {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param type
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
TypeSpec process(TypeSpec type);
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ repositories {
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':thrifty-schema')
|
compile project(':thrifty-schema')
|
||||||
compile project(':thrifty-java-codegen')
|
compile project(':thrifty-java-codegen')
|
||||||
|
compile project(':thrifty-compiler-plugins')
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.bendb.thrifty.compiler;
|
package com.bendb.thrifty.compiler;
|
||||||
|
|
||||||
|
import com.bendb.thrifty.compiler.spi.TypeProcessor;
|
||||||
import com.bendb.thrifty.gen.ThriftyCodeGenerator;
|
import com.bendb.thrifty.gen.ThriftyCodeGenerator;
|
||||||
import com.bendb.thrifty.schema.Loader;
|
import com.bendb.thrifty.schema.Loader;
|
||||||
import com.bendb.thrifty.schema.Schema;
|
import com.bendb.thrifty.schema.Schema;
|
||||||
|
@ -164,6 +165,12 @@ public class ThriftyCompiler {
|
||||||
gen = gen.withMapType(mapTypeName);
|
gen = gen.withMapType(mapTypeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypeProcessorService svc = TypeProcessorService.getInstance();
|
||||||
|
TypeProcessor processor = svc.get();
|
||||||
|
if (processor != null) {
|
||||||
|
gen = gen.usingTypeProcessor(processor);
|
||||||
|
}
|
||||||
|
|
||||||
gen.emitAndroidAnnotations(emitNullabilityAnnotations);
|
gen.emitAndroidAnnotations(emitNullabilityAnnotations);
|
||||||
|
|
||||||
gen.generate(outputDirectory);
|
gen.generate(outputDirectory);
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
dependencies {
|
||||||
|
compile project(':thrifty-compiler-plugins')
|
||||||
|
compile libraries.javaPoet
|
||||||
|
|
||||||
|
testCompile group: 'junit', name: 'junit', version: '4.11'
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.bendb.thrifty.compiler;
|
||||||
|
|
||||||
|
import com.bendb.thrifty.compiler.spi.TypeProcessor;
|
||||||
|
import com.squareup.javapoet.FieldSpec;
|
||||||
|
import com.squareup.javapoet.TypeSpec;
|
||||||
|
|
||||||
|
import javax.lang.model.element.Modifier;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An example {@link TypeProcessor} that implements {@link Serializable}
|
||||||
|
* on all types.
|
||||||
|
*/
|
||||||
|
public class SerializableTypeProcessor implements TypeProcessor {
|
||||||
|
@Override
|
||||||
|
public TypeSpec process(TypeSpec type) {
|
||||||
|
TypeSpec.Builder builder = type.toBuilder();
|
||||||
|
|
||||||
|
builder.addSuperinterface(Serializable.class);
|
||||||
|
|
||||||
|
builder.addField(FieldSpec.builder(long.class, "serialVersionUID")
|
||||||
|
.addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
|
||||||
|
.initializer("$L", -1)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
com.bendb.thrifty.compiler.SerializableTypeProcessor
|
|
@ -3,6 +3,7 @@ description = 'Converts Thrifty Schemas into Java source files'
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(":thrifty-schema")
|
compile project(":thrifty-schema")
|
||||||
compile project(":thrifty-runtime")
|
compile project(":thrifty-runtime")
|
||||||
|
compile project(":thrifty-compiler-plugins")
|
||||||
compile libraries.okio
|
compile libraries.okio
|
||||||
compile libraries.javaPoet
|
compile libraries.javaPoet
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ import com.squareup.javapoet.TypeName;
|
||||||
import com.squareup.javapoet.TypeSpec;
|
import com.squareup.javapoet.TypeSpec;
|
||||||
import org.joda.time.format.DateTimeFormatter;
|
import org.joda.time.format.DateTimeFormatter;
|
||||||
import org.joda.time.format.ISODateTimeFormat;
|
import org.joda.time.format.ISODateTimeFormat;
|
||||||
|
import com.bendb.thrifty.compiler.spi.TypeProcessor;
|
||||||
|
|
||||||
import javax.lang.model.element.Modifier;
|
import javax.lang.model.element.Modifier;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
package com.bendb.thrifty.gen;
|
|
||||||
|
|
||||||
import com.squareup.javapoet.TypeSpec;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When specified as part of code generation, processes all types after they
|
|
||||||
* are computed, but before they are written to disk. This allows you to make
|
|
||||||
* arbitrary modifications to types such as implementing your own interfaces,
|
|
||||||
* renaming fields, or anything you might wish to do.
|
|
||||||
*/
|
|
||||||
public interface TypeProcessor {
|
|
||||||
TypeSpec process(TypeSpec type);
|
|
||||||
}
|
|
Загрузка…
Ссылка в новой задаче