blob: da852e9e1998b19455127268ed9fbb4a02d5c9bb [file] [log] [blame]
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.requestfactory.rebind;
import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JField;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JParameter;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.requestfactory.client.impl.AbstractBigDecimalRequest;
import com.google.gwt.requestfactory.client.impl.AbstractBigIntegerRequest;
import com.google.gwt.requestfactory.client.impl.AbstractBooleanRequest;
import com.google.gwt.requestfactory.client.impl.AbstractByteRequest;
import com.google.gwt.requestfactory.client.impl.AbstractCharacterRequest;
import com.google.gwt.requestfactory.client.impl.AbstractDateRequest;
import com.google.gwt.requestfactory.client.impl.AbstractDoubleRequest;
import com.google.gwt.requestfactory.client.impl.AbstractEnumRequest;
import com.google.gwt.requestfactory.client.impl.AbstractFloatRequest;
import com.google.gwt.requestfactory.client.impl.AbstractIntegerRequest;
import com.google.gwt.requestfactory.client.impl.AbstractJsonListRequest;
import com.google.gwt.requestfactory.client.impl.AbstractJsonObjectRequest;
import com.google.gwt.requestfactory.client.impl.AbstractLongRequest;
import com.google.gwt.requestfactory.client.impl.AbstractShortRequest;
import com.google.gwt.requestfactory.client.impl.AbstractStringRequest;
import com.google.gwt.requestfactory.client.impl.AbstractVoidRequest;
import com.google.gwt.requestfactory.client.impl.RecordImpl;
import com.google.gwt.requestfactory.client.impl.RecordJsoImpl;
import com.google.gwt.requestfactory.client.impl.RecordSchema;
import com.google.gwt.requestfactory.client.impl.RecordToTypeMap;
import com.google.gwt.requestfactory.client.impl.RequestFactoryJsonImpl;
import com.google.gwt.requestfactory.server.ReflectionBasedOperationRegistry;
import com.google.gwt.requestfactory.shared.RecordListRequest;
import com.google.gwt.requestfactory.shared.RecordRequest;
import com.google.gwt.requestfactory.shared.RequestData;
import com.google.gwt.requestfactory.shared.RequestFactory;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import com.google.gwt.valuestore.shared.Property;
import com.google.gwt.valuestore.shared.Record;
import com.google.gwt.valuestore.shared.RecordChangedEvent;
import com.google.gwt.valuestore.shared.WriteOperation;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
/**
* <p> <span style="color:red">Experimental API: This class is still under rapid
* development, and is very likely to be deleted. Use it at your own risk.
* </span> </p> Generates implementations of {@link com.google.gwt.requestfactory.shared.RequestFactory
* RequestFactory} and its nested interfaces.
*/
public class RequestFactoryGenerator extends Generator {
private final Set<JClassType> generatedRecordTypes
= new HashSet<JClassType>();
@Override
public String generate(TreeLogger logger, GeneratorContext generatorContext,
String interfaceName) throws UnableToCompleteException {
// The TypeOracle knows about all types in the type system
TypeOracle typeOracle = generatorContext.getTypeOracle();
// Get a reference to the type that the generator should implement
JClassType interfaceType = typeOracle.findType(interfaceName);
// Ensure that the requested type exists
if (interfaceType == null) {
logger.log(TreeLogger.ERROR,
"Could not find requested typeName: " + interfaceName);
throw new UnableToCompleteException();
}
if (interfaceType.isInterface() == null) {
// The incoming type wasn't a plain interface, we don't support
// abstract base classes
logger.log(TreeLogger.ERROR,
interfaceType.getQualifiedSourceName() + " is not an interface.",
null);
throw new UnableToCompleteException();
}
String packageName = interfaceType.getPackage().getName();
// the replace protects against inner classes
String implName = interfaceType.getName().replace('.', '_') + "Impl";
PrintWriter out = generatorContext.tryCreate(logger, packageName, implName);
// If an implementation already exists, we don't need to do any work
if (out != null) {
generateOnce(typeOracle.findType(RequestFactory.class.getCanonicalName()),
logger, generatorContext, out, interfaceType, packageName, implName);
}
return packageName + "." + implName;
}
private String asInnerImplClass(String className, JClassType outerClassName) {
className = outerClassName.getQualifiedSourceName() + "Impl." + className;
return className;
}
private String capitalize(String name) {
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
private void ensureRecordType(TreeLogger logger,
GeneratorContext generatorContext, String packageName,
JClassType publicRecordType) throws UnableToCompleteException {
TypeOracle typeOracle = generatorContext.getTypeOracle();
if (!publicRecordType.isAssignableTo(typeOracle.findType(Record.class.getName()))) {
return;
}
if (generatedRecordTypes.contains(publicRecordType)) {
return;
}
String recordImplTypeName = publicRecordType.getName() + "Impl";
PrintWriter pw = generatorContext.tryCreate(logger, packageName,
recordImplTypeName);
Set<JClassType> transitiveDeps = new LinkedHashSet<JClassType>();
if (pw != null) {
logger = logger.branch(TreeLogger.DEBUG, "Generating "
+ publicRecordType.getName());
ClassSourceFileComposerFactory f = new ClassSourceFileComposerFactory(
packageName, recordImplTypeName);
String eventTypeName = publicRecordType.getName() + "Changed";
JClassType eventType = typeOracle.findType(packageName, eventTypeName);
if (eventType == null) {
logger.log(TreeLogger.ERROR,
String.format("Cannot find %s implementation %s.%s",
RecordChangedEvent.class.getName(), packageName,
eventTypeName));
throw new UnableToCompleteException();
}
f.addImport(AbstractJsonListRequest.class.getName());
f.addImport(AbstractJsonObjectRequest.class.getName());
f.addImport(RequestFactoryJsonImpl.class.getName());
f.addImport(Property.class.getName());
f.addImport(Record.class.getName());
f.addImport(RecordImpl.class.getName());
f.addImport(RecordJsoImpl.class.getName());
f.addImport(RecordSchema.class.getName());
f.addImport(WriteOperation.class.getName().replace("$", "."));
f.addImport(Collections.class.getName());
f.addImport(HashSet.class.getName());
f.addImport(Set.class.getName());
f.addImport(Map.class.getName());
f.addImport(HashMap.class.getName());
f.setSuperclass(RecordImpl.class.getSimpleName());
f.addImplementedInterface(publicRecordType.getName());
SourceWriter sw = f.createSourceWriter(generatorContext, pw);
sw.println();
JClassType propertyType = printSchema(typeOracle, publicRecordType,
recordImplTypeName, eventType, sw);
sw.println();
String simpleImplName = publicRecordType.getSimpleSourceName() + "Impl";
printRequestImplClass(sw, publicRecordType, simpleImplName, true);
printRequestImplClass(sw, publicRecordType, simpleImplName, false);
sw.println();
sw.println(String.format(
"public static final RecordSchema<%s> SCHEMA = new MySchema();",
recordImplTypeName));
sw.println();
sw.println(String.format("private %s(RecordJsoImpl jso, boolean isFuture) {",
recordImplTypeName));
sw.indent();
sw.println("super(jso, isFuture);");
sw.outdent();
sw.println("}");
// getter methods
for (JField field : publicRecordType.getFields()) {
JType fieldType = field.getType();
if (propertyType.getErasedType() == fieldType.getErasedType()) {
JParameterizedType parameterized = fieldType.isParameterized();
if (parameterized == null) {
logger.log(TreeLogger.ERROR,
fieldType + " must have its param type set.");
throw new UnableToCompleteException();
}
JClassType returnType = parameterized.getTypeArgs()[0];
sw.println();
sw.println(String.format("public %s get%s() {",
returnType.getQualifiedSourceName(),
capitalize(field.getName())));
sw.indent();
sw.println(String.format("return get(%s);", field.getName()));
sw.outdent();
sw.println("}");
/*
* Because a Proxy A may relate to B which relates to C, we need to
* ensure transitively.
*/
if (isRecordType(typeOracle, returnType)) {
transitiveDeps.add(returnType);
}
}
}
// setter methods
for (JField field : publicRecordType.getFields()) {
JType fieldType = field.getType();
if (propertyType.getErasedType() == fieldType.getErasedType()) {
JParameterizedType parameterized = fieldType.isParameterized();
if (parameterized == null) {
logger.log(TreeLogger.ERROR, fieldType
+ " must have its param type set.");
throw new UnableToCompleteException();
}
JClassType returnType = parameterized.getTypeArgs()[0];
sw.println();
String varName = field.getName();
sw.println(String.format("public void set%s(%s %s) {",
capitalize(field.getName()), returnType.getQualifiedSourceName(),
varName));
sw.indent();
sw.println(String.format("set(this.%s, this, %s);", field.getName(), varName));
sw.outdent();
sw.println("}");
}
}
sw.outdent();
sw.println("}");
generatorContext.commit(logger, pw);
}
generatedRecordTypes.add(publicRecordType);
// ensure generatation of transitive dependencies
for (JClassType type : transitiveDeps) {
ensureRecordType(logger, generatorContext, type.getPackage().getName(),
type);
}
}
private void generateOnce(JClassType requestFactoryType, TreeLogger logger,
GeneratorContext generatorContext, PrintWriter out,
JClassType interfaceType, String packageName, String implName)
throws UnableToCompleteException {
logger = logger.branch(TreeLogger.DEBUG,
String.format("Generating implementation of %s",
interfaceType.getName()));
ClassSourceFileComposerFactory f = new ClassSourceFileComposerFactory(
packageName, implName);
f.addImport(HandlerManager.class.getName());
f.addImport(RequestFactoryJsonImpl.class.getName());
f.addImport(interfaceType.getQualifiedSourceName());
f.addImport(RecordToTypeMap.class.getName());
f.addImport(Record.class.getName());
f.addImport(RecordSchema.class.getName());
f.addImplementedInterface(interfaceType.getName());
f.setSuperclass(RequestFactoryJsonImpl.class.getSimpleName());
SourceWriter sw = f.createSourceWriter(generatorContext, out);
sw.println();
// Find the requestSelector methods
// TODO allow getRequest type methods to live directly on the factory, w/o
// requiring a selector to get to them
// TODO rename variable this requestBuilders, holding off to avoid merge
// hell
Set<JMethod> requestSelectors = new LinkedHashSet<JMethod>();
for (JMethod method : interfaceType.getOverridableMethods()) {
if (method.getEnclosingType().equals(requestFactoryType)) {
continue;
}
JType returnType = method.getReturnType();
if (null == returnType) {
logger.log(TreeLogger.ERROR, String.format(
"Illegal return type for %s. Methods of %s must return interfaces, found void",
method.getName(), interfaceType.getName()));
throw new UnableToCompleteException();
}
JClassType asInterface = returnType.isInterface();
if (null == asInterface) {
logger.log(TreeLogger.ERROR, String.format(
"Illegal return type for %s. Methods of %s must return interfaces",
method.getName(), interfaceType.getName()));
throw new UnableToCompleteException();
}
requestSelectors.add(method);
}
// In addition to the request selectors in the generated interface, there
// are a few which are in RequestFactory which also need to have
// implementations generated. Hard coding the addition of these here for now
JClassType t = generatorContext.getTypeOracle().findType(
RequestFactory.class.getName());
try {
requestSelectors.add(t.getMethod("loggingRequest", new JType[0]));
} catch (NotFoundException e) {
e.printStackTrace();
}
JClassType recordToTypeInterface = generatorContext.getTypeOracle().findType(RecordToTypeMap.class.getName());
// TODO: note, this seems like a bug. What if you have 2 RequestFactories?
String recordToTypeMapName = recordToTypeInterface.getName() + "Impl";
// write create(Class)
sw.println("public " + Record.class.getName() + " create(Class token) {");
sw.indent();
sw.println("return create(token, new " + recordToTypeMapName + "());");
sw.outdent();
sw.println("}");
sw.println();
// write getClass(String)
sw.println("public Class<? extends " + Record.class.getName() + "> getClass(String token) {");
sw.indent();
sw.println("return getClass(token, new " + recordToTypeMapName + "());");
sw.outdent();
sw.println("}");
sw.println();
// write getProxy(String)
sw.println("public " + Record.class.getName() + " getProxy(String token) {");
sw.indent();
sw.println("return getProxy(token, new " + recordToTypeMapName + "());");
sw.outdent();
sw.println("}");
sw.println();
// write getToken(Record)
sw.println("public String getToken(Record record) {");
sw.indent();
sw.println("return getToken(record, new " + recordToTypeMapName + "());");
sw.outdent();
sw.println("}");
sw.println();
// write getToken(Class)
sw.println("public String getToken(Class clazz) {");
sw.indent();
sw.println("return new " + recordToTypeMapName + "().getClassToken(clazz);");
sw.outdent();
sw.println("}");
sw.println();
sw.println(
"public RecordSchema<? extends Record> getSchema(String schemaToken) {");
sw.indent();
sw.println("return new " + recordToTypeMapName + "().getType(schemaToken);");
sw.outdent();
sw.println("}");
// write a method for each request builder and generate it
for (JMethod requestSelector : requestSelectors) {
String returnTypeName = requestSelector.getReturnType().getQualifiedSourceName();
String nestedImplName =
capitalize(requestSelector.getName().replace('.', '_')) + "Impl";
String nestedImplPackage = generatorContext.getTypeOracle().findType(
returnTypeName).getPackage().getName();
sw.println("public " + returnTypeName + " " + requestSelector.getName()
+ "() {");
sw.indent();
sw.println(
"return new " + nestedImplPackage + "." + nestedImplName + "(this);");
sw.outdent();
sw.println("}");
sw.println();
PrintWriter pw = generatorContext.tryCreate(logger, nestedImplPackage,
nestedImplName);
if (pw != null) {
generateRequestSelectorImplementation(logger, generatorContext, pw,
requestSelector, interfaceType, nestedImplPackage, nestedImplName);
}
}
// close the class
sw.outdent();
sw.println("}");
// generate the mapping type implementation
PrintWriter pw = generatorContext.tryCreate(logger, packageName,
recordToTypeMapName);
if (pw != null) {
generateRecordToTypeMap(logger, generatorContext, pw,
recordToTypeInterface, packageName, recordToTypeMapName);
}
generatorContext.commit(logger, out);
}
private void generateRecordToTypeMap(TreeLogger logger,
GeneratorContext generatorContext, PrintWriter out,
JClassType interfaceType, String packageName, String implName) {
logger = logger.branch(TreeLogger.DEBUG,
String.format("Generating implementation of %s",
interfaceType.getName()));
ClassSourceFileComposerFactory f = new ClassSourceFileComposerFactory(
packageName, implName);
f.addImport(interfaceType.getQualifiedSourceName());
f.addImport(Record.class.getName());
f.addImport(RecordSchema.class.getName());
f.addImport(interfaceType.getQualifiedSourceName());
f.addImplementedInterface(interfaceType.getName());
f.addImplementedInterface(interfaceType.getName());
SourceWriter sw = f.createSourceWriter(generatorContext, out);
sw.println();
sw.println("public <R extends Record> RecordSchema<R> getType(Class<R> recordClass) {");
sw.indent();
for (JClassType publicRecordType : generatedRecordTypes) {
String qualifiedSourceName = publicRecordType.getQualifiedSourceName();
sw.println("if (recordClass == " + qualifiedSourceName + ".class) {");
sw.indent();
sw.println("return (RecordSchema<R>) " + qualifiedSourceName + "Impl.SCHEMA;");
sw.outdent();
sw.println("}");
}
sw.println(
"throw new IllegalArgumentException(\"Unknown recordClass \" + recordClass);");
sw.indent();
sw.outdent();
sw.outdent();
sw.println("}");
sw.println("public RecordSchema<? extends Record> getType(String token) {");
sw.indent();
sw.println("String[] bits = token.split(\"-\");");
for (JClassType publicRecordType : generatedRecordTypes) {
String qualifiedSourceName = publicRecordType.getQualifiedSourceName();
sw.println("if (bits[0].equals(\"" + qualifiedSourceName + "\")) {");
sw.indent();
sw.println("return " + qualifiedSourceName + "Impl.SCHEMA;");
sw.outdent();
sw.println("}");
}
sw.println("throw new IllegalArgumentException(\"Unknown string token: \" + token);");
sw.outdent();
sw.println("}");
sw.println("public String getClassToken(Class<?> recordClass) {");
sw.indent();
for (JClassType publicRecordType : generatedRecordTypes) {
String qualifiedSourceName = publicRecordType.getQualifiedSourceName();
sw.println("if (recordClass == " + qualifiedSourceName + ".class) {");
sw.indent();
sw.println("return \"" + qualifiedSourceName + "\";");
sw.outdent();
sw.println("}");
}
sw.println(
"throw new IllegalArgumentException(\"Unknown recordClass \" + recordClass);");
sw.indent();
sw.outdent();
sw.outdent();
sw.println("}");
sw.outdent();
sw.println("}");
sw.println();
generatorContext.commit(logger, out);
}
private void generateRequestSelectorImplementation(TreeLogger logger,
GeneratorContext generatorContext, PrintWriter out,
JMethod selectorMethod, JClassType mainType, String packageName,
String implName) throws UnableToCompleteException {
JClassType selectorInterface = selectorMethod.getReturnType().isInterface();
logger = logger.branch(TreeLogger.DEBUG,
String.format("Generating implementation of %s",
selectorInterface.getName()));
ClassSourceFileComposerFactory f = new ClassSourceFileComposerFactory(
packageName, implName);
f.addImport(RequestData.class.getName());
f.addImport(mainType.getQualifiedSourceName() + "Impl");
f.addImplementedInterface(selectorInterface.getQualifiedSourceName());
SourceWriter sw = f.createSourceWriter(generatorContext, out);
sw.println();
sw.println("private final " + mainType.getName() + "Impl factory;");
sw.println();
// constructor for the class.
sw.println(
"public " + implName + "(" + mainType.getName() + "Impl factory) {");
sw.indent();
sw.println("this.factory = factory;");
sw.outdent();
sw.println("}");
sw.println();
// write each method.
for (JMethod method : selectorInterface.getOverridableMethods()) {
JClassType returnType = method.getReturnType().isParameterized().getTypeArgs()[0];
ensureRecordType(logger, generatorContext,
returnType.getPackage().getName(), returnType);
String operationName = selectorInterface.getQualifiedBinaryName()
+ ReflectionBasedOperationRegistry.SCOPE_SEPARATOR + method.getName();
JClassType requestType = method.getReturnType().isClassOrInterface();
String requestClassName = null;
TypeOracle typeOracle = generatorContext.getTypeOracle();
String enumArgument = "";
// TODO: refactor this into some kind of extensible map lookup
if (isRecordListRequest(typeOracle, requestType)) {
requestClassName = asInnerImplClass("ListRequestImpl", returnType);
} else if (isRecordRequest(typeOracle, requestType)) {
requestClassName = asInnerImplClass("ObjectRequestImpl", returnType);
} else if (isStringRequest(typeOracle, requestType)) {
requestClassName = AbstractStringRequest.class.getName();
} else if (isLongRequest(typeOracle, requestType)) {
requestClassName = AbstractLongRequest.class.getName();
} else if (isIntegerRequest(typeOracle, requestType)) {
requestClassName = AbstractIntegerRequest.class.getName();
} else if (isDoubleRequest(typeOracle, requestType)) {
requestClassName = AbstractDoubleRequest.class.getName();
} else if (isByteRequest(typeOracle, requestType)) {
requestClassName = AbstractByteRequest.class.getName();
} else if (isBooleanRequest(typeOracle, requestType)) {
requestClassName = AbstractBooleanRequest.class.getName();
} else if (isShortRequest(typeOracle, requestType)) {
requestClassName = AbstractShortRequest.class.getName();
} else if (isFloatRequest(typeOracle, requestType)) {
requestClassName = AbstractFloatRequest.class.getName();
} else if (isCharacterRequest(typeOracle, requestType)) {
requestClassName = AbstractCharacterRequest.class.getName();
} else if (isDateRequest(typeOracle, requestType)) {
requestClassName = AbstractDateRequest.class.getName();
} else if (isBigDecimalRequest(typeOracle, requestType)) {
requestClassName = AbstractBigDecimalRequest.class.getName();
} else if (isBigIntegerRequest(typeOracle, requestType)) {
requestClassName = AbstractBigIntegerRequest.class.getName();
} else if (isEnumRequest(typeOracle, requestType)) {
requestClassName = AbstractEnumRequest.class.getName();
enumArgument = ", " + requestType.isParameterized().getTypeArgs()[0]
+ ".values()";
} else if (isVoidRequest(typeOracle, requestType)) {
requestClassName = AbstractVoidRequest.class.getName();
} else {
logger.log(TreeLogger.ERROR,
"Return type " + requestType + " is not yet supported");
throw new UnableToCompleteException();
}
sw.println(getMethodDeclaration(method) + " {");
sw.indent();
sw.println(
"return new " + requestClassName + "(factory" + enumArgument + ") {");
sw.indent();
String requestDataName = RequestData.class.getSimpleName();
sw.println("public " + requestDataName + " getRequestData() {");
sw.indent();
sw.println(
"return new " + requestDataName + "(\"" + operationName + "\", "
+ getParametersAsString(method, typeOracle) + ","
+ "getPropertyRefs());");
sw.outdent();
sw.println("}");
sw.outdent();
sw.println("};");
sw.outdent();
sw.println("}");
}
sw.outdent();
sw.println("}");
generatorContext.commit(logger, out);
}
/**
* This method is very similar to {@link com.google.gwt.core.ext.typeinfo.JMethod.getReadableDeclaration()}.
* The only change is that each parameter is final.
*/
private String getMethodDeclaration(JMethod method) {
StringBuilder sb = new StringBuilder("public ");
sb.append(method.getReturnType().getParameterizedQualifiedSourceName());
sb.append(" ");
sb.append(method.getName());
sb.append("(");
boolean needComma = false;
for (JParameter param : method.getParameters()) {
if (needComma) {
sb.append(", ");
} else {
needComma = true;
}
sb.append("final "); // so that an anonymous class can refer it
sb.append(param.getType().getParameterizedQualifiedSourceName());
sb.append(" ");
sb.append(param.getName());
}
sb.append(")");
return sb.toString();
}
/**
* Returns the string representation of the parameters to be passed to the
* server side method.
*/
private String getParametersAsString(JMethod method, TypeOracle typeOracle) {
StringBuilder sb = new StringBuilder();
for (JParameter parameter : method.getParameters()) {
if (sb.length() > 0) {
sb.append(", ");
}
JClassType classType = parameter.getType().isClassOrInterface();
JType paramType = parameter.getType();
boolean isRef =
"com.google.gwt.valuestore.shared.PropertyReference".equals(
paramType.getQualifiedBinaryName());
JParameterizedType params = paramType.isParameterized();
if (params != null) {
classType = params.getTypeArgs()[0];
}
if (classType != null
&& classType.isAssignableTo(typeOracle.findType(Record.class.getName()))) {
sb.append("((" + classType.getQualifiedBinaryName() + "Impl" + ")");
}
sb.append(parameter.getName());
// TODO No. This defeats the entire purpose of PropertyReference. It's
// supposed
// to be dereferenced server side, not client side.
if (isRef) {
sb.append(".get()");
}
if (classType != null
&& classType.isAssignableTo(typeOracle.findType(Record.class.getName()))) {
sb.append(").getUniqueId()");
}
}
return "new Object[] {" + sb.toString() + "}";
}
private boolean isBigDecimalRequest(TypeOracle typeOracle,
JClassType requestType) {
return requestType.isParameterized().getTypeArgs()[0].isAssignableTo(typeOracle.findType(BigDecimal.class.getName()));
}
private boolean isBigIntegerRequest(TypeOracle typeOracle,
JClassType requestType) {
return requestType.isParameterized().getTypeArgs()[0].isAssignableTo(typeOracle.findType(BigInteger.class.getName()));
}
private boolean isBooleanRequest(TypeOracle typeOracle,
JClassType requestType) {
return requestType.isParameterized().getTypeArgs()[0].isAssignableTo(typeOracle.findType(Boolean.class.getName()));
}
private boolean isByteRequest(TypeOracle typeOracle, JClassType requestType) {
return requestType.isParameterized().getTypeArgs()[0].isAssignableTo(typeOracle.findType(Byte.class.getName()));
}
private boolean isCharacterRequest(TypeOracle typeOracle,
JClassType requestType) {
return requestType.isParameterized().getTypeArgs()[0].isAssignableTo(typeOracle.findType(Character.class.getName()));
}
private boolean isDateRequest(TypeOracle typeOracle, JClassType requestType) {
return requestType.isParameterized().getTypeArgs()[0].isAssignableTo(typeOracle.findType(Date.class.getName()));
}
private boolean isDoubleRequest(TypeOracle typeOracle,
JClassType requestType) {
return requestType.isParameterized().getTypeArgs()[0].isAssignableTo(typeOracle.findType(Double.class.getName()));
}
private boolean isEnumRequest(TypeOracle typeOracle, JClassType requestType) {
return requestType.isParameterized().getTypeArgs()[0].isAssignableTo(typeOracle.findType(Enum.class.getName()));
}
private boolean isFloatRequest(TypeOracle typeOracle,
JClassType requestType) {
return requestType.isParameterized().getTypeArgs()[0].isAssignableTo(typeOracle.findType(Float.class.getName()));
}
private boolean isIntegerRequest(TypeOracle typeOracle,
JClassType requestType) {
return requestType.isParameterized().getTypeArgs()[0].isAssignableTo(typeOracle.findType(Integer.class.getName()));
}
private boolean isLongRequest(TypeOracle typeOracle, JClassType requestType) {
return requestType.isParameterized().getTypeArgs()[0].isAssignableTo(typeOracle.findType(Long.class.getName()));
}
private boolean isRecordListRequest(TypeOracle typeOracle,
JClassType requestType) {
return requestType.isAssignableTo(typeOracle.findType(RecordListRequest.class.getName()));
}
private boolean isRecordRequest(TypeOracle typeOracle,
JClassType requestType) {
return requestType.isAssignableTo(typeOracle.findType(RecordRequest.class.getName()));
}
private boolean isRecordType(TypeOracle typeOracle, JClassType requestType) {
return requestType.isAssignableTo(typeOracle.findType(Record.class.getName()));
}
private boolean isShortRequest(TypeOracle typeOracle,
JClassType requestType) {
return requestType.isParameterized().getTypeArgs()[0].isAssignableTo(typeOracle.findType(Short.class.getName()));
}
private boolean isStringRequest(TypeOracle typeOracle,
JClassType requestType) {
return requestType.isParameterized().getTypeArgs()[0].isAssignableTo(typeOracle.findType(String.class.getName()));
}
private boolean isVoidRequest(TypeOracle typeOracle, JClassType requestType) {
return requestType.isParameterized().getTypeArgs()[0].isAssignableTo(typeOracle.findType(Void.class.getName()));
}
/**
* Prints a ListRequestImpl or ObjectRequestImpl class.
*/
private void printRequestImplClass(SourceWriter sw, JClassType returnType,
String returnImplTypeName, boolean list) {
String name = list ? "ListRequestImpl" : "ObjectRequestImpl";
Class<?> superClass = list ? AbstractJsonListRequest.class
: AbstractJsonObjectRequest.class;
sw.println("public static abstract class " + name + " extends "
+ superClass.getSimpleName() + "<" + returnType.getName() + ", " + name
+ "> {");
sw.println();
sw.indent();
sw.println(String.format("%s(%s factory) {", name,
RequestFactoryJsonImpl.class.getSimpleName()));
sw.indent();
sw.println("super(" + returnImplTypeName + ".SCHEMA, factory);");
sw.outdent();
sw.println("}");
sw.println();
sw.println("@Override");
sw.println("protected " + name + " getThis() {");
sw.indent();
sw.println("return this;");
sw.outdent();
sw.println("}");
sw.outdent();
sw.println("}");
sw.println();
}
/**
* @param typeOracle
* @param publicRecordType
* @param recordImplTypeName
* @param eventType
* @param sw
* @return
* @throws UnableToCompleteException
*/
private JClassType printSchema(TypeOracle typeOracle,
JClassType publicRecordType, String recordImplTypeName,
JClassType eventType, SourceWriter sw) {
sw.println(
String.format("public static class MySchema extends RecordSchema<%s> {",
recordImplTypeName));
sw.indent();
sw.println("private final Set<Property<?>> allProperties;");
sw.println("{");
sw.indent();
sw.println("Set<Property<?>> set = new HashSet<Property<?>>();");
sw.println("set.addAll(super.allProperties());");
JClassType propertyType;
try {
propertyType = typeOracle.getType(Property.class.getName());
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
for (JField field : publicRecordType.getFields()) {
if (propertyType.getErasedType() == field.getType().getErasedType()) {
sw.println(String.format("set.add(%s);", field.getName()));
}
}
sw.println("allProperties = Collections.unmodifiableSet(set);");
sw.outdent();
sw.println("}");
sw.println();
sw.println("public Set<Property<?>> allProperties() {");
sw.indent();
sw.println("return allProperties;");
sw.outdent();
sw.println("}");
sw.println();
sw.println("public MySchema() {");
sw.indent();
sw.println("super(\"" + publicRecordType.getQualifiedSourceName() + "\");");
sw.outdent();
sw.println("}");
sw.println();
sw.println("@Override");
sw.println(String.format("public %s create(RecordJsoImpl jso, boolean isFuture) {",
recordImplTypeName));
sw.indent();
sw.println(String.format("return new %s(jso, isFuture);", recordImplTypeName));
sw.outdent();
sw.println("}");
sw.println();
sw.println("@Override");
sw.println(String.format(
"public %s createChangeEvent(Record record, WriteOperation writeOperation) {",
eventType.getName()));
sw.indent();
sw.println(String.format("return new %s((%s) record, writeOperation);",
eventType.getName(), publicRecordType.getName()));
sw.outdent();
sw.println("}");
sw.println();
sw.println("public Class getProxyClass() {");
sw.indent();
sw.println("return " + publicRecordType.getQualifiedSourceName() + ".class;"
+ " // special field");
sw.outdent();
sw.println("}");
sw.outdent();
sw.println("}");
return propertyType;
}
}