@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(); }
@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(); }
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 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(); }
@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); } }