@Override public void writeFieldReadStatement( VariableElement field, Collection<ExecutableElement> postCreateChildMethods, JavaWriter writer) throws IOException { DeclaredType type = (DeclaredType) field.asType(); TypeMirror itemType = type.getTypeArguments().get(0); TypeMirror itemTypeErasure = processingEnv.getTypeUtils().erasure(itemType); String collectionInitializer; try { collectionInitializer = initializers.findCollectionInitializer(type); } catch (InvalidTypeException e) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage(), field); collectionInitializer = "null"; } writer.beginControlFlow("if (bundle.containsKey(\"%s\"))", field.getSimpleName()); writer.emitStatement("object.%s = %s", field.getSimpleName(), collectionInitializer); writer.emitStatement( "%1$s.readCollectionFromBundle(object.%2$s, bundle, %3$s.class, \"%2$s\")", CollectionBundler.class.getCanonicalName(), field.getSimpleName(), itemTypeErasure); writePostCreateChildMethodCalls(field, itemType, postCreateChildMethods, writer); writer.endControlFlow(); }
private void createHeader( Set<? extends Element> annotatedElements, String packageName, JavaWriter writer) throws IOException { writer.emitPackage(packageName); Map<String, Element> nonRepeatedImports = new HashMap<>(); for (Element element : annotatedElements) { TypeMirror elementType = element.asType(); if (isSubtypeOfType(elementType, "android.view.View")) { nonRepeatedImports.put(element.asType().toString(), element); } else { processingEnv .getMessager() .printMessage( Diagnostic.Kind.ERROR, String.format( "Variable: %s, is not of a type that subclasses android.view.View. @%s can only be used with Views", element.getSimpleName().toString(), InjectView.class.getSimpleName())); } } for (String importString : nonRepeatedImports.keySet()) { writer.emitImports(importString); } }
public String getJavaTypeName(final Type type, final boolean sequence, final JavaWriter writer) { final String typeName; if (type instanceof Message) { if (sequence) { typeName = writer.compressType(getSequenceTypeName(type.getCanonicalName())); } else { typeName = type.getCanonicalName(); } } else if (type.isPrimitive()) { if (isEnumDeclaration(type)) { return Names.capitalize(type.getCanonicalName()); } Class<?> clazz = getJavaClass(type); if (sequence) { String itemClassName = getSequenceItemClassName(clazz); typeName = writer.compressType(getSequenceTypeName(itemClassName)); } else { typeName = writer.compressType(clazz.getCanonicalName()); } } else { throw new UnsupportedOperationException( "Cannot resolve Java type for " + type + ", sequence: " + sequence); } return typeName; }
@Override public void writeFieldWriteStatement(VariableElement field, JavaWriter writer) throws IOException { DeclaredType type = (DeclaredType) field.asType(); TypeMirror itemType = type.getTypeArguments().get(0); TypeMirror itemTypeErasure = processingEnv.getTypeUtils().erasure(itemType); writer.beginControlFlow("if (object.%s != null)", field.getSimpleName()); writer.emitStatement( "%1$s.writeCollectionToBundle(object.%2$s, bundle, %3$s.class, \"%2$s\")", CollectionBundler.class.getCanonicalName(), field.getSimpleName(), itemTypeErasure); writer.endControlFlow(); }
@Override public void handle(ProcessorManager processorManager, RoundEnvironment roundEnvironment) { for (BaseContainerHandler containerHandler : handlers) { containerHandler.handle(processorManager, roundEnvironment); } ContentProviderValidator validator = new ContentProviderValidator(); Collection<ContentProviderDefinition> contentProviderDefinitions = providerMap.values(); for (ContentProviderDefinition contentProviderDefinition : contentProviderDefinitions) { if (validator.validate(processorManager, contentProviderDefinition)) { WriterUtils.writeBaseDefinition(contentProviderDefinition, processorManager); } } List<DatabaseWriter> databaseWriters = getManagerWriters(); for (DatabaseWriter databaseWriter : databaseWriters) { try { JavaWriter javaWriter = new JavaWriter( processorManager .getProcessingEnvironment() .getFiler() .createSourceFile(databaseWriter.getSourceFileName()) .openWriter()); databaseWriter.write(javaWriter); javaWriter.close(); } catch (IOException e) { processorManager.getMessager().printMessage(Diagnostic.Kind.WARNING, e.getMessage()); } } if (roundEnvironment.processingOver()) { try { JavaWriter staticFlowManager = new JavaWriter( processorManager .getProcessingEnvironment() .getFiler() .createSourceFile( Classes.FLOW_MANAGER_PACKAGE + "." + Classes.DATABASE_HOLDER_STATIC_CLASS_NAME) .openWriter()); new FlowManagerHolderWriter(processorManager).write(staticFlowManager); staticFlowManager.close(); } catch (IOException e) { processorManager.getMessager().printMessage(Diagnostic.Kind.WARNING, e.getMessage()); } } }
private void writePostCreateChildMethodCalls( VariableElement field, TypeMirror itemType, Collection<ExecutableElement> postCreateChildMethods, JavaWriter writer) throws IOException { if (!postCreateChildMethods.isEmpty() && metaTypes.isSubtype(itemType, Names.PARCELABLE)) { writer.beginControlFlow("for (Object child : object.%s)", field.getSimpleName()); for (ExecutableElement method : postCreateChildMethods) { writer.emitStatement("object.%s(child)", method.getSimpleName()); } writer.endControlFlow(); } }
public static void emitPreferenceCommitAction( JavaWriter writer, PreferenceEditorCommitStyle commitStyle, StringBuilder statementPattern) throws IOException { String statement = String.format(statementPattern.toString(), commitStyle.getStatementPart()); writer.emitStatement(statement); }
public void write(final Type type, final EnumConstraint<String> constraint) throws IOException { JavaWriter jw = javaClassWriter.getOutput(); jw.emitPackage(options.getPackageName()); javaClassWriter.writeImports(Collections.<String>emptySet()); if (type.getDescription() != null) { jw.emitJavadoc(type.getDescription()); } String enumName = Names.capitalize(type.getCanonicalName()); jw.beginType(enumName, "enum", EnumSet.of(PUBLIC)); Iterator<String> valuesIterator = constraint.getValues().iterator(); while (valuesIterator.hasNext()) { String value = valuesIterator.next(); javaClassWriter.writeEnumValue(value, !valuesIterator.hasNext()); } jw.endType(); }
private void emitStatements( Set<? extends Element> annotatedElements, String hostActivityname, JavaWriter writer) throws IOException { for (Element element : annotatedElements) { writer.emitStatement( "((" + hostActivityname + ")target)." + element.getSimpleName().toString() + " = " + "(" + element.asType().toString() + ")target.findViewById(" + element.getAnnotation(InjectView.class).value() + ")"); } }
public void generate() throws IOException { String qualifiedGeneratedClassName = String.format("%s.%s", Constants.REALM_PACKAGE_NAME, Constants.DEFAULT_MODULE_CLASS_NAME); JavaFileObject sourceFile = env.getFiler().createSourceFile(qualifiedGeneratedClassName); JavaWriter writer = new JavaWriter(new BufferedWriter(sourceFile.openWriter())); writer.setIndent(" "); writer.emitPackage(Constants.REALM_PACKAGE_NAME); writer.emitEmptyLine(); Map<String, Boolean> attributes = new HashMap<String, Boolean>(); attributes.put("allClasses", Boolean.TRUE); writer.emitAnnotation(RealmModule.class, attributes); writer.beginType( qualifiedGeneratedClassName, // full qualified name of the item to generate "class", // the type of the item Collections.<Modifier>emptySet(), // modifiers to apply null); // class to extend writer.emitEmptyLine(); writer.endType(); writer.close(); }
public static void emitFillRealmObjectFromStream( String setter, String fieldName, String fieldTypeCanonicalName, String proxyClass, JavaWriter writer) throws IOException { writer .beginControlFlow("if (reader.peek() == JsonToken.NULL)") .emitStatement("reader.skipValue()") .emitStatement("obj.%s(null)", setter) .nextControlFlow("else") .emitStatement( "%s %sObj = %s.createUsingJsonStream(realm, reader)", fieldTypeCanonicalName, fieldName, proxyClass) .emitStatement("obj.%s(%sObj)", setter, fieldName) .endControlFlow(); }
public static void emitFillRealmObjectWithJsonValue( String setter, String fieldName, String qualifiedFieldType, String proxyClass, JavaWriter writer) throws IOException { writer .beginControlFlow("if (json.has(\"%s\"))", fieldName) .beginControlFlow("if (json.isNull(\"%s\"))", fieldName) .emitStatement("obj.%s(null)", setter) .nextControlFlow("else") .emitStatement( "%s %sObj = %s.createOrUpdateUsingJsonObject(realm, json.getJSONObject(\"%s\"), update)", qualifiedFieldType, fieldName, proxyClass, fieldName) .emitStatement("obj.%s(%sObj)", setter, fieldName) .endControlFlow() .endControlFlow(); }
@Override public void emitStreamTypeConversion( String setter, String fieldName, String fieldType, JavaWriter writer) throws IOException { String statementSetNullOrThrow; if (Utils.isPrimitiveType(fieldType)) { // Only throw exception for primitive types. For boxed types and String, exception will be // thrown in // the setter. statementSetNullOrThrow = String.format(Constants.STATEMENT_EXCEPTION_ILLEGAL_NULL_VALUE, fieldName); } else { statementSetNullOrThrow = String.format("obj.%s(null)", setter); } writer .beginControlFlow("if (reader.peek() == JsonToken.NULL)") .emitStatement("reader.skipValue()") .emitStatement(statementSetNullOrThrow) .nextControlFlow("else") .emitStatement("obj.%s((%s) reader.next%s())", setter, castType, jsonType) .endControlFlow(); }
public static void emitFillRealmListFromStream( String getter, String setter, String fieldTypeCanonicalName, String proxyClass, JavaWriter writer) throws IOException { writer .beginControlFlow("if (reader.peek() == JsonToken.NULL)") .emitStatement("reader.skipValue()") .emitStatement("obj.%s(null)", setter) .nextControlFlow("else") .emitStatement("reader.beginArray()") .beginControlFlow("while (reader.hasNext())") .emitStatement( "%s item = %s.createUsingJsonStream(realm, reader)", fieldTypeCanonicalName, proxyClass) .emitStatement("obj.%s().add(item)", getter) .endControlFlow() .emitStatement("reader.endArray()") .endControlFlow(); }
public static void emitFillRealmListWithJsonValue( String getter, String setter, String fieldName, String fieldTypeCanonicalName, String proxyClass, JavaWriter writer) throws IOException { writer .beginControlFlow("if (json.has(\"%s\"))", fieldName) .beginControlFlow("if (json.isNull(\"%s\"))", fieldName) .emitStatement("obj.%s(null)", setter) .nextControlFlow("else") .emitStatement("obj.%s().clear()", getter) .emitStatement("JSONArray array = json.getJSONArray(\"%s\")", fieldName) .beginControlFlow("for (int i = 0; i < array.length(); i++)") .emitStatement( "%s item = %s.createOrUpdateUsingJsonObject(realm, array.getJSONObject(i), update)", fieldTypeCanonicalName, proxyClass, fieldTypeCanonicalName) .emitStatement("obj.%s().add(item)", getter) .endControlFlow() .endControlFlow() .endControlFlow(); }
private void beginType(String newSourceName, JavaWriter writer) throws IOException { writer.beginType(newSourceName, "class", EnumSet.of(Modifier.PUBLIC)); }
private void beginMethod(String hostActivityname, JavaWriter writer) throws IOException { writer.beginMethod("void", "inject", EnumSet.of(Modifier.PUBLIC), hostActivityname, "target"); }
private void emitClose(JavaWriter writer) throws IOException { writer.endMethod(); writer.endType(); writer.close(); }
@SuppressWarnings({"unchecked", "ConstantConditions"}) private void manageType(TypeElement enclosingElement, Logger logger) { // Make sure we don't process twice the same type String simpleName = enclosingElement.getSimpleName().toString(); String qualifiedName = enclosingElement.getQualifiedName().toString(); String packageName = Utils.getElementPackageName(enclosingElement); if (managedTypes.contains(qualifiedName)) return; managedTypes.add(qualifiedName); // Prepare the output file try { JavaFileObject classFile = processingEnv.getFiler().createSourceFile(qualifiedName + INJECTOR_SUFFIX); logger.note("Writing " + classFile.toUri().getRawPath()); Writer out = classFile.openWriter(); JavaWriter writer = new JavaWriter(out); writer.emitPackage(packageName); // Initial imports writer .emitImports(AsyncService.class, Injector.class, Message.class, Set.class, HashSet.class) .emitImports( "com.joanzapata.android.asyncservice.api.annotation.OnMessage.Priority", "android.os.Handler", "android.os.Looper") .emitStaticImports( "com.joanzapata.android.asyncservice.api.annotation.OnMessage.Priority.*"); // Generates "public final class XXXInjector extends Injector<XXX>" writer .emitEmptyLine() .beginType( simpleName + INJECTOR_SUFFIX, "class", of(PUBLIC, FINAL), "Injector<" + simpleName + ">"); // Generate a handler to execute runnables on the UI Thread writer .emitEmptyLine() .emitField( "Handler", "__handler", of(PRIVATE, FINAL), "new Handler(Looper.getMainLooper())"); // Keep trace of when a method has received data which is not from cache writer .emitEmptyLine() .emitField( "Set<String>", "__receivedFinalResponses", of(PRIVATE, FINAL), "new HashSet<String>()"); // Generates "protected void inject(XXX target) { ..." writer .emitEmptyLine() .emitAnnotation(Override.class) .beginMethod("void", "inject", of(PROTECTED), simpleName, "target"); // Here, inject all services List<Element> elementsAnnotatedWith = findElementsAnnotatedWith(enclosingElement, InjectService.class); for (Element element : elementsAnnotatedWith) { if (isPublicOrPackagePrivate(element)) { writer.emitStatement( "target.%s = new %s(target)", element.getSimpleName(), element.asType().toString() + AsyncServiceAP.GENERATED_CLASS_SUFFIX); } } // End of inject() writer.endMethod().emitEmptyLine(); // Generates "protected void dispatch(XXX target, Message event)" writer .emitAnnotation(Override.class) .beginMethod( "void", "dispatch", of(PROTECTED), "final " + simpleName, "target", "final " + Message.class.getSimpleName(), "event", Priority.class.getSimpleName(), "priority"); // Once the user has received a "remote" result, make sure no cache is sent anymore writer .emitField( "boolean", "__hasBeenReceivedAlready", of(FINAL), "event.getQuery() != null && __receivedFinalResponses.contains(event.getQuery())") .emitStatement("if (event.isCached() && __hasBeenReceivedAlready) return") .emitStatement( "if (!__hasBeenReceivedAlready && !event.isCached() && priority == LAST) __receivedFinalResponses.add(event.getQuery())"); // Here, dispatch events to methods List<Element> responseReceivers = findElementsAnnotatedWith(enclosingElement, OnMessage.class); for (Element responseReceiver : responseReceivers) { ExecutableElement annotatedMethod = (ExecutableElement) responseReceiver; AnnotationMirror annotationMirror = getAnnotation(annotatedMethod, OnMessage.class); List<? extends VariableElement> parameters = annotatedMethod.getParameters(); if (parameters.size() > 1) logger.error( responseReceiver, "@OnMessage annotated methods can't have more than 1 argument"); // Define event type given parameter or @InjectResponse value List<String> eventTypes; boolean hasArg = parameters.size() == 1; if (hasArg) { TypeMirror typeMirror = parameters.get(0).asType(); eventTypes = asList(typeMirror.toString()); if (hasTypeParameters(processingEnv, typeMirror)) logger.error( parameters.get(0), "You can't receive typed parameters in @OnMessage annotated methods"); } else { List<AnnotationValue> parameterTypeClasses = getAnnotationValue(annotationMirror, "value"); // Validate each parameter type given in the annotation eventTypes = new ArrayList<String>(); for (AnnotationValue value : parameterTypeClasses) { DeclaredType parameterTypeClass = (DeclaredType) value.getValue(); if (parameterTypeClass == null) logger.error( annotatedMethod, "Either declare an argument or give @OnMessage a value."); if (hasTypeParameters(processingEnv, parameterTypeClass)) logger.error( annotatedMethod, annotationMirror, "value", "You can't receive typed parameters in @OnMessage method"); eventTypes.add(parameterTypeClass.toString()); } } // Define whether we should check emitter or not dependeing on the annotation value VariableElement from = getAnnotationValue(annotationMirror, "from"); boolean checkEmitter = !ALL.toString().equals("" + from); // Check the priority of the method VariableElement priorityValue = getAnnotationValue(annotationMirror, "priority"); Priority priority = !LAST.toString().equals("" + priorityValue) ? FIRST : LAST; writer.beginControlFlow("if (priority == %s)", priority); // Write the code to call the user method if (checkEmitter) writer.beginControlFlow("if (event.getEmitter() == getTarget())"); // Create a new inner class for the Runnable to run on UI thread StringWriter buffer = new StringWriter(); JavaWriter inner = new JavaWriter(buffer); inner .emitPackage("") .beginType("Runnable()", "new") .emitAnnotation("Override") .beginMethod("void", "run", of(PUBLIC)); if (hasArg) inner.emitStatement( "target.%s((%s) event.getPayload())", annotatedMethod.getSimpleName(), eventTypes.get(0)); else inner.emitStatement("target.%s()", annotatedMethod.getSimpleName()); inner.endMethod().endType(); // For each type (can be multiple) for (int i = 0; i < eventTypes.size(); i++) { String eventType = eventTypes.get(i); writer .beginControlFlow( "%sif (event.getPayload() instanceof %s)", i != 0 ? "else " : "", eventType) .emitStatement("__handler.post(%s)", buffer.toString()) .endControlFlow(); } if (checkEmitter) writer.endControlFlow(); writer.endControlFlow(); } // End of inject(); writer.endMethod().emitEmptyLine(); // End of file writer.endType(); out.flush(); out.close(); } catch (IOException e) { throw new IllegalStateException("Error while create the injector for " + qualifiedName, e); } }