Last active
August 29, 2015 14:07
-
-
Save rhmoller/7aebcfa928ebfd190784 to your computer and use it in GitHub Desktop.
GWT-RPC Linter that checks that serializable interfaces have implementations and serializable classes have default constructors and serializable fields. Should be invoked from a GWT Generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class GwtRpcLinter { | |
public static final String PACKAGE_PREFIX = "com.yourcompany"; // only check classes in this package | |
private TreeLogger logger; | |
private GeneratorContext context; | |
private List<String> errorMessages = new ArrayList<>(); | |
public GwtRpcLinter(TreeLogger logger, GeneratorContext context) { | |
this.logger = logger; | |
this.context = context; | |
} | |
public void run() throws UnableToCompleteException { | |
TreeLogger lintLogger = logger.branch(TreeLogger.Type.WARN, "GWT-RPC Linter started"); | |
JClassType type = context.getTypeOracle().findType("com.google.gwt.user.client.rpc.IsSerializable"); | |
checkSubTypes(type); | |
JClassType type2 = context.getTypeOracle().findType("java.io.Serializable"); | |
checkSubTypes(type2); | |
if (errorMessages.isEmpty()) { | |
lintLogger.log(TreeLogger.Type.INFO, "GWT-RPC Linter completed without errors"); | |
} else { | |
lintLogger.log(TreeLogger.Type.WARN, "GWT-RPC Linter failed with " + errorMessages.size() + " errors"); | |
for (String errorMessage : errorMessages) { | |
System.err.println(errorMessage); | |
lintLogger.log(TreeLogger.Type.WARN, errorMessage); | |
} | |
// todo: raise level to ERROR and throw this exception when we are sure it does the right thing. | |
// throw new UnableToCompleteException(); | |
} | |
} | |
private void checkSubTypes(JClassType type) { | |
JClassType[] serializableTypes = type.getSubtypes(); | |
for (JClassType serializableType : serializableTypes) { | |
if (serializableType.getPackage().getName().startsWith(PACKAGE_PREFIX)) { | |
if (isSerializableInterfaceWithoutImplementation(serializableType)) { | |
errorMessages.add("Serializable/IsSerializable interface " + serializableType + " has no implementation."); | |
} | |
if (isConcreteClass(serializableType)) { | |
if (!hasDefaultConstructor(serializableType)) { | |
errorMessages.add("Serializable/IsSerializable class " + serializableType + " has no default constructor."); | |
} | |
JField[] fields = serializableType.getFields(); | |
for (JField field : fields) { | |
boolean serializableField = isSerializableOrTransientField(field); | |
if (!serializableField) { | |
errorMessages.add("Serializable/IsSerializable class " + serializableType + " has non-transient field " + field.getName() + " that is not serializable"); | |
} | |
} | |
} | |
} | |
} | |
} | |
private boolean isSerializableOrTransientField(JField field) { | |
boolean serializableField = false; | |
JClassType fieldClass = field.getType().isClassOrInterface(); | |
if (fieldClass != null && !field.isTransient()) { | |
JClassType[] interfaces = fieldClass.getImplementedInterfaces(); | |
for (JClassType anInterface : interfaces) { | |
if ("com.google.gwt.user.client.rpc.IsSerializable".equals(anInterface.getName()) || | |
"java.io.Serializable".equals(anInterface.getName())) { | |
serializableField = true; | |
} | |
} | |
} else { | |
serializableField = true; | |
} | |
return serializableField; | |
} | |
private boolean hasDefaultConstructor(JClassType serializableType) { | |
if (serializableType.getConstructors().length == 0) return true; | |
try { | |
JConstructor defaultConstructor = serializableType.getConstructor(new JType[]{}); | |
return true; | |
} catch (NotFoundException e) { | |
return false; | |
} | |
} | |
private boolean isConcreteClass(JClassType serializableType) { | |
return !(serializableType.isAbstract() || serializableType.isInterface() == null); | |
} | |
private boolean isSerializableInterfaceWithoutImplementation(JClassType serializableType) { | |
return serializableType.isInterface() != null && serializableType.getSubtypes().length == 0; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment