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-gradle-plugin'
|
||||
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 {
|
||||
compile project(':thrifty-schema')
|
||||
compile project(':thrifty-java-codegen')
|
||||
compile project(':thrifty-compiler-plugins')
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.bendb.thrifty.compiler;
|
||||
|
||||
import com.bendb.thrifty.compiler.spi.TypeProcessor;
|
||||
import com.bendb.thrifty.gen.ThriftyCodeGenerator;
|
||||
import com.bendb.thrifty.schema.Loader;
|
||||
import com.bendb.thrifty.schema.Schema;
|
||||
|
@ -164,6 +165,12 @@ public class ThriftyCompiler {
|
|||
gen = gen.withMapType(mapTypeName);
|
||||
}
|
||||
|
||||
TypeProcessorService svc = TypeProcessorService.getInstance();
|
||||
TypeProcessor processor = svc.get();
|
||||
if (processor != null) {
|
||||
gen = gen.usingTypeProcessor(processor);
|
||||
}
|
||||
|
||||
gen.emitAndroidAnnotations(emitNullabilityAnnotations);
|
||||
|
||||
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 {
|
||||
compile project(":thrifty-schema")
|
||||
compile project(":thrifty-runtime")
|
||||
compile project(":thrifty-compiler-plugins")
|
||||
compile libraries.okio
|
||||
compile libraries.javaPoet
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ import com.squareup.javapoet.TypeName;
|
|||
import com.squareup.javapoet.TypeSpec;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.joda.time.format.ISODateTimeFormat;
|
||||
import com.bendb.thrifty.compiler.spi.TypeProcessor;
|
||||
|
||||
import javax.lang.model.element.Modifier;
|
||||
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);
|
||||
}
|
Загрузка…
Ссылка в новой задаче