package xapi.dev.gwtc.impl; import xapi.dev.X_Gwtc; import xapi.dev.gwtc.api.GwtcService; import xapi.dev.source.ClassBuffer; import xapi.dev.source.FieldBuffer; import xapi.dev.source.MethodBuffer; import xapi.dev.source.SourceBuilder; import xapi.gwtc.api.DefaultValue; import xapi.log.X_Log; import xapi.source.X_Source; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.reflect.shared.GwtReflect; import javax.inject.Inject; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.LinkedHashMap; import java.util.Map; public class GwtcEntryPointBuilder { private GwtcService gwtc; protected final MethodBuffer out; private final ClassBuffer cls; private final Map<String, String> instanceProviders; public GwtcEntryPointBuilder(SourceBuilder<GwtcService> gwtc) { this.gwtc = gwtc.getPayload(); this.cls = gwtc.getClassBuffer(); out = cls.addInterface(EntryPoint.class) .createMethod("void onModuleLoad"); instanceProviders = new LinkedHashMap<>(); } public void println(String text) { out.println(text); } public String formatInstanceCall(Method method, boolean onNewInstance) { String cls = formatInstanceProvider(method.getDeclaringClass()); StringBuilder b = new StringBuilder(); b.append(cls).append("."); b.append(formatMethodCall(method)); b.append(";"); return b.toString(); } public String formatInstanceProvider(Class<?> declaringClass) { String field = instanceProviders.get(declaringClass.getCanonicalName()); if (field == null) { X_Log.trace(getClass(), "Generating instance field for ",declaringClass); field = X_Source.toStringEnclosed(declaringClass).replace('.', '_'); field = Character.toLowerCase(field.charAt(0)) + field.substring(1); instanceProviders.put(declaringClass.getCanonicalName(), field); FieldBuffer buffer = cls.createField(declaringClass, field, Modifier.PRIVATE | Modifier.FINAL); StringBuilder b = new StringBuilder() .append("new ") .append(cls.addImport(declaringClass)) .append("("); // Find the best constructor Constructor<?> winner = null; Constructor<?>[] ctors = declaringClass.getConstructors(); search: for (int i = ctors.length; i --> 0;) { Constructor<?> ctor = ctors[i]; if (ctor.getAnnotation(Inject.class) != null) { // Backup default, we'll accept @Inject constructors winner = ctor; } for (Annotation[] annos : ctor.getParameterAnnotations()) { for (Annotation anno : annos) { if (anno instanceof DefaultValue) { winner = ctor; break search; } } } } if (winner == null) { winner = GwtReflect.getPublicConstructor(declaringClass); } if (winner == null) { String error = "Cannot instantiate instance of "+declaringClass.getCanonicalName()+"; " + "as it does not have an any public constructors annotated with " + "@DefaultValue, or a zero-arg public constructor."; IllegalArgumentException exception = new IllegalArgumentException(error); X_Log.error(getClass(), error, exception); throw exception; } b.append(formatParameters(winner.getParameterTypes(), winner.getParameterAnnotations())); buffer.setInitializer(b+");"); } return field; } public String formatMethodCall(Method method) { StringBuilder b = new StringBuilder(); b.append(method.getName()).append("("); b.append(formatParameters(method.getParameterTypes(), method.getParameterAnnotations())); return b.append(")").toString(); } public String formatParameters(Class<?>[] params, Annotation[][] annos) { StringBuilder b = new StringBuilder(); for (int i = 0, m = params.length; i < m; i++){ Class<?> param = params[i]; DefaultValue value = X_Gwtc.getDefaultValue(param, annos[i]); if (value == null) { b.append("null"); } else { b.append(value.value()); } if (i > 0) { b.append(", "); } } return b.toString(); } public String formatStaticCall(Method method) { String clazz = cls.addImport(method.getDeclaringClass()); StringBuilder b = new StringBuilder(); b .append(clazz) .append(".") .append(formatMethodCall(method)) .append(";"); return b.toString(); } }