All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nuiton.jaxx.compiler.finalizers.DefaultFinalizer Maven / Gradle / Ivy

The newest version!
/*
 * #%L
 * JAXX :: Compiler
 * %%
 * Copyright (C) 2008 - 2024 Code Lutin, Ultreia.io
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

package org.nuiton.jaxx.compiler.finalizers;

import com.google.auto.service.AutoService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.codehaus.plexus.component.annotations.Component;
import org.nuiton.jaxx.compiler.CompiledObject;
import org.nuiton.jaxx.compiler.CompiledObjectDecorator;
import org.nuiton.jaxx.compiler.CompilerException;
import org.nuiton.jaxx.compiler.EventHandler;
import org.nuiton.jaxx.compiler.JAXXCompiler;
import org.nuiton.jaxx.compiler.binding.DataBinding;
import org.nuiton.jaxx.compiler.binding.writers.DefaultJAXXBindingWriter;
import org.nuiton.jaxx.compiler.binding.writers.JAXXBindingWriter;
import org.nuiton.jaxx.compiler.binding.writers.SimpleJAXXObjectBindingWriter;
import org.nuiton.jaxx.compiler.java.JavaArgument;
import org.nuiton.jaxx.compiler.java.JavaElementFactory;
import org.nuiton.jaxx.compiler.java.JavaField;
import org.nuiton.jaxx.compiler.java.JavaFile;
import org.nuiton.jaxx.compiler.java.JavaFileGenerator;
import org.nuiton.jaxx.compiler.java.JavaMethod;
import org.nuiton.jaxx.compiler.reflect.ClassDescriptor;
import org.nuiton.jaxx.compiler.reflect.ClassDescriptorHelper;
import org.nuiton.jaxx.compiler.reflect.MethodDescriptor;
import org.nuiton.jaxx.compiler.types.TypeManager;
import org.nuiton.jaxx.runtime.Base64Coder;
import org.nuiton.jaxx.runtime.JAXXBinding;
import org.nuiton.jaxx.runtime.JAXXContext;
import org.nuiton.jaxx.runtime.JAXXObject;
import org.nuiton.jaxx.runtime.JAXXObjectDescriptor;
import org.nuiton.jaxx.runtime.JAXXUtil;
import org.nuiton.jaxx.runtime.spi.UIHandler;
import org.nuiton.jaxx.runtime.swing.SwingUtil;

import java.awt.Container;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import static java.lang.reflect.Modifier.ABSTRACT;
import static java.lang.reflect.Modifier.FINAL;
import static java.lang.reflect.Modifier.PRIVATE;
import static java.lang.reflect.Modifier.PROTECTED;
import static java.lang.reflect.Modifier.PUBLIC;
import static java.lang.reflect.Modifier.STATIC;
import static java.lang.reflect.Modifier.isProtected;
import static java.lang.reflect.Modifier.isPublic;
import static org.nuiton.jaxx.compiler.java.JavaElementFactory.newArgument;
import static org.nuiton.jaxx.compiler.java.JavaElementFactory.newField;
import static org.nuiton.jaxx.compiler.java.JavaElementFactory.newMethod;

/**
 * This class is a refactoring of the {@link JAXXCompiler}.
 * 

* We delegate now the generation of a {@link JAXXObject} to this class, the * {@link JAXXCompiler} now only deals with the compilation of files. * * @author Tony Chemit - [email protected] */ @AutoService(JAXXCompilerFinalizer.class) @Component(hint = "default", role = JAXXCompilerFinalizer.class) public class DefaultFinalizer extends AbstractFinalizer { public static final String FIELD_NAME_$BINDING_SOURCES = "$bindingSources"; public static final String FIELD_NAME_$OBJECT_MAP = "$objectMap"; public static final String FIELD_NAME_$ACTIVE_BINDINGS = "$activeBindings"; public static final String FIELD_NAME_$PREVIOUS_VALUES = "$previousValues"; public static final String FIELD_NAME_$BINDINGS = "$bindings"; public static final String FIELD_NAME_$PROPERTY_CHANGE_SUPPORT = "$propertyChangeSupport"; public static final String FIELD_NAME_DELEGATE_CONTEXT = "delegateContext"; public static final String FIELD_NAME_SERIAL_VERSION_UID = "serialVersionUID"; public static final String FIELD_NAME_$JAXX_OBJECT_DESCRIPTOR = "$jaxxObjectDescriptor"; public static final String METHOD_NAME_$GET_JAXX_OBJECT_DESCRIPTOR = "$getJAXXObjectDescriptor"; public static final String METHOD_NAME_REGISTER_DATA_BINDING = "registerDataBinding"; public static final String METHOD_NAME_REMOVE_DATA_BINDING = "removeDataBinding"; public static final String METHOD_NAME_APPLY_DATA_BINDING = "applyDataBinding"; public static final String METHOD_NAME_PROCESS_DATA_BINDING = "processDataBinding"; public static final String METHOD_NAME_FIRE_PROPERTY_CHANGE = "firePropertyChange"; public static final String METHOD_NAME_$GET_PROPERTY_CHANGE_SUPPORT = "$getPropertyChangeSupport"; public static final String METHOD_NAME_$INITIALIZE = "$initialize"; public static final String METHOD_NAME_$INITIALIZE_01_CREATE_HANDLER = "$initialize_01_createHandler"; public static final String METHOD_NAME_$INITIALIZE_01_CREATE_COMPONENTS = "$initialize_01_createComponents"; public static final String METHOD_NAME_$INITIALIZE_02_REGISTER_DATA_BINDINGS = "$initialize_02_registerDataBindings"; public static final String METHOD_NAME_$INITIALIZE_03_FINALIZE_CREATE_COMPONENTS = "$initialize_03_finalizeCreateComponents"; public static final String METHOD_NAME_$INITIALIZE_03_REGISTER_ACTIONS = "$initialize_03_registerActions"; public static final String METHOD_NAME_$INITIALIZE_04_APPLY_DATA_BINDINGS = "$initialize_04_applyDataBindings"; public static final String METHOD_NAME_$INITIALIZE_05_SET_PROPERTIES = "$initialize_05_setProperties"; public static final String METHOD_NAME_$INITIALIZE_06_FINALIZE_INITIALIZE = "$initialize_06_finalizeInitialize"; public static final String METHOD_$INITIALIZER_CALL = "" + "JAXXObject.initialize(%1$s" + " this,%1$s" + " this::%2$s,%1$s" + " this::%3$s,%1$s" + " this::%4$s,%1$s" + " this::%5$s,%1$s" + " this::%6$s,%1$s" + " this::%7$s,%1$s" + " this::%8$s,%1$s" + " this::%9$s);%1$s"; /** * Logger. */ protected static final Logger log = LogManager.getLogger(DefaultFinalizer.class); /** * serialVersionUID field */ protected static final JavaField SERIAL_VERSION_UID_FIELD = newField( PRIVATE | STATIC | FINAL, "long", FIELD_NAME_SERIAL_VERSION_UID, false, "1L" ); /** * */ protected static final JavaField ACTIVE_BINDINGS_FIELD = newField( PROTECTED, List.class.getName() + "<" + TYPE_OBJECT + ">", FIELD_NAME_$ACTIVE_BINDINGS, false, "new %s<" + TYPE_OBJECT + ">()", ArrayList.class.getName() ); /** * */ protected static final JavaField BINDING_SOURCES_FIELD = newField( PROTECTED, Map.class.getName() + "<" + TYPE_STRING + ", " + TYPE_OBJECT + ">", FIELD_NAME_$BINDING_SOURCES, false, "new %s<" + TYPE_STRING + ", " + TYPE_OBJECT + ">()", HashMap.class.getName() ); /** * */ protected static final JavaField OBJECT_MAP_FIELD = newField( PROTECTED, Map.class.getName() + "<" + TYPE_STRING + ", " + TYPE_OBJECT + ">", FIELD_NAME_$OBJECT_MAP, true, "new %s<" + TYPE_STRING + ", " + TYPE_OBJECT + ">()", HashMap.class.getName() ); /** * */ protected static final JavaField PREVIOUS_VALUES_FIELD = newField( PROTECTED, Map.class.getName() + "", FIELD_NAME_$PREVIOUS_VALUES, false, "new %s<" + TYPE_OBJECT + ", " + TYPE_OBJECT + ">()", HashMap.class.getName() ); /** * */ protected static final JavaField BINDINGS_FIELD = newField( PROTECTED | FINAL, Map.class.getName() + "<" + TYPE_STRING + ", " + JAXXBinding.class.getName() + ">", FIELD_NAME_$BINDINGS, false, "new %s<" + TYPE_STRING + ", %s>()", TreeMap.class.getName(), JAXXBinding.class.getName() ); /** * */ protected static final JavaField PROPERTY_CHANGE_SUPPORT_FIELD = newField( PROTECTED, PropertyChangeSupport.class.getName(), FIELD_NAME_$PROPERTY_CHANGE_SUPPORT, false ); /** * */ protected static final JavaMethod GET_CONTEXT_VALUE_METHOD = newMethod( PUBLIC, " T", "getContextValue", "return " + FIELD_NAME_DELEGATE_CONTEXT + ".getContextValue(clazz, null);", true, newArgument("Class", "clazz") ); /** * */ protected static final JavaMethod GET_CONTEXT_VALUE_NAMED_METHOD = newMethod( PUBLIC, " T", "getContextValue", "return " + FIELD_NAME_DELEGATE_CONTEXT + ".getContextValue(clazz, name);", true, newArgument("Class", "clazz"), newArgument(TYPE_STRING, "name") ); /** * */ protected static final JavaMethod SET_CONTEXT_VALUE_NAMED_METHOD = newMethod( PUBLIC, " " + TYPE_VOID, "setContextValue", FIELD_NAME_DELEGATE_CONTEXT + ".setContextValue(o, name);", true, newArgument("T", "o"), newArgument(TYPE_STRING, "name")); /** * */ protected static final JavaMethod SET_CONTEXT_VALUE_METHOD = newMethod( PUBLIC, " " + TYPE_VOID, "setContextValue", FIELD_NAME_DELEGATE_CONTEXT + ".setContextValue(o, null);", true, newArgument("T", "o") ); /** * */ protected static final JavaMethod REMOVE_CONTEXT_VALUE_NAMED_METHOD = newMethod( PUBLIC, " " + TYPE_VOID, "removeContextValue", FIELD_NAME_DELEGATE_CONTEXT + ".removeContextValue(clazz, name);", true, newArgument("Class", "clazz"), newArgument(TYPE_STRING, "name") ); /** * */ protected static final JavaMethod REMOVE_CONTEXT_VALUE_METHOD = newMethod( PUBLIC, " " + TYPE_VOID, "removeContextValue", FIELD_NAME_DELEGATE_CONTEXT + ".removeContextValue(clazz, null);", true, newArgument("Class", "clazz") ); /** * */ protected static final JavaMethod GET_PARENT_CONTAINER_MORE_METHOD = newMethod( PUBLIC, " O", "getParentContainer", "return %s.getParentContainer(source, clazz);", true, newArgument(TYPE_OBJECT, "source"), newArgument("Class", "clazz") ); /** * */ protected static final JavaMethod GET_PARENT_CONTAINER_METHOD = newMethod( PUBLIC, " O", "getParentContainer", "return %s.getParentContainer(this, clazz);", true, newArgument("Class", "clazz") ); /** * */ protected static final JavaMethod GET_OBJECT_BY_ID_METHOD = newMethod( PUBLIC, TYPE_OBJECT, "getObjectById", "return " + FIELD_NAME_$OBJECT_MAP + ".get(id);", true, newArgument(TYPE_STRING, "id") ); /** * */ protected static final JavaMethod GET_JAXX_OBJECT_DESCRIPTOR_METHOD = newMethod( PUBLIC | STATIC, JAXXObjectDescriptor.class.getName(), METHOD_NAME_$GET_JAXX_OBJECT_DESCRIPTOR, "return %s.decodeCompressedJAXXObjectDescriptor(" + FIELD_NAME_$JAXX_OBJECT_DESCRIPTOR + ");", false ); /** * */ protected static final JavaMethod REGISTER_DATA_BINDING_METHOD = newMethod( PUBLIC, TYPE_VOID, METHOD_NAME_REGISTER_DATA_BINDING, FIELD_NAME_$BINDINGS + ".put(binding.getId(), binding);", true, newArgument(JAXXBinding.class.getName(), "binding") ); /** * */ protected static final JavaMethod GET_DATA_BINDINGS_METHOD = newMethod( PUBLIC, JAXXBinding.class.getName() + "[]", "getDataBindings", "return " + FIELD_NAME_$BINDINGS + ".values().toArray(new %s[" + FIELD_NAME_$BINDINGS + ".size()]);", true ); /** * */ protected static final JavaMethod GET_DATA_BINDING_METHOD = newMethod( PUBLIC, JAXXBinding.class.getName(), "getDataBinding", "return " + FIELD_NAME_$BINDINGS + ".get(bindingId);", true, newArgument(TYPE_STRING, "bindingId") ); /** * */ protected static final JavaMethod FIRE_PROPERTY_CHANGE_METHOD = newMethod( PUBLIC, TYPE_VOID, METHOD_NAME_FIRE_PROPERTY_CHANGE, "super." + METHOD_NAME_FIRE_PROPERTY_CHANGE + "(propertyName, oldValue, newValue);", true, newArgument(TYPE_STRING, "propertyName"), newArgument(TYPE_OBJECT, "oldValue"), newArgument(TYPE_OBJECT, "newValue") ); /** * */ protected static final JavaMethod FIRE_PROPERTY_CHANGE_NAMED_METHOD = newMethod( PUBLIC, TYPE_VOID, METHOD_NAME_FIRE_PROPERTY_CHANGE, METHOD_NAME_$GET_PROPERTY_CHANGE_SUPPORT + "()." + METHOD_NAME_FIRE_PROPERTY_CHANGE + "(propertyName, oldValue, newValue);", true, newArgument(TYPE_STRING, "propertyName"), newArgument(TYPE_OBJECT, "oldValue"), newArgument(TYPE_OBJECT, "newValue") ); /** * */ protected static final JavaMethod GET_PROPERTY_CHANGE_SUPPORT_METHOD = newMethod( 0, PropertyChangeSupport.class.getName(), METHOD_NAME_$GET_PROPERTY_CHANGE_SUPPORT, "if (" + FIELD_NAME_$PROPERTY_CHANGE_SUPPORT + " == null)\n" + " " + FIELD_NAME_$PROPERTY_CHANGE_SUPPORT + " = new PropertyChangeSupport(this);\n" + "return " + FIELD_NAME_$PROPERTY_CHANGE_SUPPORT + ";", false ); /** * */ protected static final JavaMethod ADD_PROPERTY_CHANGE_SUPPORT_METHOD = newMethod( PUBLIC, TYPE_VOID, "addPropertyChangeListener", METHOD_NAME_$GET_PROPERTY_CHANGE_SUPPORT + "().addPropertyChangeListener(listener);", true, newArgument(PropertyChangeListener.class.getName(), "listener") ); /** * */ protected static final JavaMethod ADD_PROPERTY_CHANGE_SUPPORT_NAMED_METHOD = newMethod( PUBLIC, TYPE_VOID, "addPropertyChangeListener", METHOD_NAME_$GET_PROPERTY_CHANGE_SUPPORT + "().addPropertyChangeListener(property, listener);", true, newArgument(TYPE_STRING, "property"), newArgument(PropertyChangeListener.class.getName(), "listener") ); /** * */ protected static final JavaMethod REMOVE_PROPERTY_CHANGE_SUPPORT_METHOD = newMethod( PUBLIC, TYPE_VOID, "removePropertyChangeListener", METHOD_NAME_$GET_PROPERTY_CHANGE_SUPPORT + "().removePropertyChangeListener(listener);", true, newArgument(PropertyChangeListener.class.getName(), "listener") ); /** * */ protected static final JavaMethod REMOVE_PROPERTY_CHANGE_SUPPORT_NAMED_METHOD = newMethod( PUBLIC, TYPE_VOID, "removePropertyChangeListener", METHOD_NAME_$GET_PROPERTY_CHANGE_SUPPORT + "().removePropertyChangeListener(property, listener);", true, newArgument(TYPE_STRING, "property"), newArgument(PropertyChangeListener.class.getName(), "listener") ); private static final String PARAMETER_NAME_$BINDING = "$binding"; /** * */ protected static final JavaMethod PROCESS_DATA_BINDING_METHOD = newMethod( PUBLIC, TYPE_VOID, METHOD_NAME_PROCESS_DATA_BINDING, METHOD_NAME_PROCESS_DATA_BINDING + "(" + PARAMETER_NAME_$BINDING + ", false);", true, newArgument(TYPE_STRING, PARAMETER_NAME_$BINDING) ); protected final JAXXBindingWriter[] bindingWriters = new JAXXBindingWriter[]{new SimpleJAXXObjectBindingWriter(), new DefaultJAXXBindingWriter() }; @Override public boolean accept(JAXXCompiler compiler) { // alwyas use the default finalizer return true; } @Override public void finalizeCompiler(CompiledObject root, JAXXCompiler compiler, JavaFile javaFile, String packageName, String className) throws ClassNotFoundException { String fullClassName = packageName != null ? packageName + "." + className : className; if (root == null) { throw new CompilerException("root tag can not be null"); } ClassDescriptor superclass = root.getObjectClass(); boolean superclassIsJAXXObject = compiler.isSuperClassAware(JAXXObject.class); javaFile.setModifiers(PUBLIC); javaFile.setName(fullClassName); javaFile.setSimpleName(className); javaFile.setSuperClass(JAXXCompiler.getCanonicalName(superclass)); javaFile.setSuperclassIsJAXXObject(superclassIsJAXXObject); javaFile.addInterface(compiler.getExtraInterfaces()); javaFile.setAbstractClass(compiler.isAbstractClass()); javaFile.setGenericType(compiler.getGenericType()); javaFile.setSuperGenericType(compiler.getSuperGenericType()); if (!superclassIsJAXXObject) { javaFile.addInterface(JAXXObject.class.getName()); } } @Override public void prepareJavaFile(CompiledObject root, JAXXCompiler compiler, JavaFile javaFile, String packageName, String className) { // add logger support if required addLoggerSupport(compiler, javaFile, className); // add JAXXObject support if required addJAXXObjectSupport(compiler, root, javaFile); addSimpleField(javaFile, SERIAL_VERSION_UID_FIELD); addJAXXObjectDescriptorField(compiler, javaFile); addMethod(javaFile, GET_JAXX_OBJECT_DESCRIPTOR_METHOD, JAXXUtil.class.getName()); addPreviousValuesField(compiler, javaFile, root); DataBinding[] bindings = compiler.getBindingHelper().getDataBindings(); addInitializerMethod(compiler, javaFile); addInitialize_01_createHandler(compiler, javaFile, className); addInitialize_01_createComponents(compiler, javaFile); addInitialize_02_registerActions(compiler, javaFile); addInitialize_02_registerDataBindings(compiler, javaFile); addInitialize_03_finalizeCreateComponents(compiler, javaFile); addInitialize_04_applyDataBindings(compiler, javaFile); addInitialize_05_setProperties(compiler, javaFile); addInitialize_06_finalizeInitialize(compiler, javaFile); javaFile.addBodyCode(compiler.getBodyCode().toString()); addDataBindings(compiler, javaFile, bindings); addEventHandlers(compiler, javaFile); } protected void addDataBindings(JAXXCompiler compiler, JavaFile javaFile, DataBinding[] bindings) { if (bindings.length < 1) { // no data bindings return; } // add import on each type of JAXXBinding used for (JAXXBindingWriter writer : bindingWriters) { if (writer.isUsed()) { javaFile.addImport(writer.getType()); } } // for each binding declare the constant Id for (DataBinding binding : bindings) { String constantId = binding.getConstantId(); // add the data binding constant Id compiler.addSimpleField(newField( (constantId.startsWith("BINDING_$") ? PRIVATE : PUBLIC) | FINAL | STATIC, TYPE_STRING, constantId, false, TypeManager.getJavaCode(binding.getRealId())) ); } } protected void addJAXXObjectSupport(JAXXCompiler compiler, CompiledObject root, JavaFile javaFile) { String jaxxContextImplementorClass = compiler.getConfiguration().getJaxxContextClass().getName(); boolean superclassIsJAXXObject = javaFile.isSuperclassIsJAXXObject(); if (superclassIsJAXXObject) { //FIXME tchemit 2011-01-30 : We should not add it (if user want to use it in script it must add the correct import // Will be removed in version 3.0 with strict imports features javaFile.addImport(JAXXContext.class); } else { // add JAXXObject support addField(javaFile, OBJECT_MAP_FIELD); addSimpleField(javaFile, BINDING_SOURCES_FIELD); addSimpleField(javaFile, ACTIVE_BINDINGS_FIELD); addSimpleField(javaFile, BINDINGS_FIELD); javaFile.addMethod(GET_OBJECT_BY_ID_METHOD); addMethod(javaFile, REGISTER_DATA_BINDING_METHOD); addMethod(javaFile, GET_DATA_BINDINGS_METHOD, JAXXBinding.class.getSimpleName()); addMethod(javaFile, GET_DATA_BINDING_METHOD, JAXXBinding.class.getSimpleName()); javaFile.addMethod(createApplyDataBindingMethod()); javaFile.addMethod(createProcessDataBindingMethod()); javaFile.addMethod(createRemoveDataBindingMethod()); // JAXXContext String type = javaFile.getImportedType(jaxxContextImplementorClass); javaFile.addField(newField( PROTECTED | FINAL, JAXXContext.class.getName(), FIELD_NAME_DELEGATE_CONTEXT, true, "new " + type + "()") ); javaFile.addImport(Container.class); javaFile.addMethod(SET_CONTEXT_VALUE_METHOD); javaFile.addMethod(SET_CONTEXT_VALUE_NAMED_METHOD); javaFile.addMethod(GET_CONTEXT_VALUE_METHOD); javaFile.addMethod(GET_CONTEXT_VALUE_NAMED_METHOD); javaFile.addMethod(REMOVE_CONTEXT_VALUE_METHOD); javaFile.addMethod(REMOVE_CONTEXT_VALUE_NAMED_METHOD); addMethod(javaFile, GET_PARENT_CONTAINER_METHOD, SwingUtil.class.getName()); addMethod(javaFile, GET_PARENT_CONTAINER_MORE_METHOD, SwingUtil.class.getName()); // PropertyChangeSupport addPropertyChangeSupport(root, javaFile); // DataBinding javaFile.addMethod(PROCESS_DATA_BINDING_METHOD); } } protected void addLoggerSupport(JAXXCompiler compiler, JavaFile javaFile, String className) { if (compiler.getConfiguration().isAddLogger()) { javaFile.addSimpleField(newField( PRIVATE | STATIC | FINAL, Logger.class.getName(), "log", false, "%s.getLogger(" + className + ".class)", LogManager.class.getName() ) ); } } /*---------------------------------------------------------------------------------*/ /*-- Create fields ----------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/ protected JavaField addJAXXObjectDescriptorField(JAXXCompiler compiler, JavaFile javaFile) { JavaField field; try { JAXXObjectDescriptor descriptor = compiler.getJAXXObjectDescriptor(); String data = Base64Coder.serialize(descriptor, true); /*ByteArrayOutputStream buffer = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(new GZIPOutputStream(buffer)); out.writeObject(descriptor); out.close(); // the use of the weird deprecated constructor is deliberate -- we need to store the data as a String // in the compiled class file, since byte array initialization is horribly inefficient compared to // String initialization. So we store the bytes in the String, and we quite explicitly want a 1:1 // mapping between bytes and chars, with the high byte of the char set to zero. We can then safely // reconstitute the original byte[] at a later date. This is unquestionably an abuse of the String // type, but if we could efficiently store a byte[] we wouldn't have to do this. String data = new String(buffer.toByteArray(), 0);*/ int sizeLimit = 65000; // constant strings are limited to 64K, and I'm not brave enough to push right up to the limit if (data.length() < sizeLimit) { field = newField(PRIVATE | STATIC | FINAL, TYPE_STRING, FIELD_NAME_$JAXX_OBJECT_DESCRIPTOR, false, TypeManager.getJavaCode(data) ); } else { StringBuilder initializer = new StringBuilder(); for (int i = 0; i < data.length(); i += sizeLimit) { String name = FIELD_NAME_$JAXX_OBJECT_DESCRIPTOR + i; javaFile.addField(newField( PRIVATE | STATIC, TYPE_STRING, name, false, TypeManager.getJavaCode(data.substring(i, Math.min(i + sizeLimit, data.length())))) ); if (initializer.length() > 0) { initializer.append(" + "); } initializer.append(TYPE_STRING + ".valueOf("); initializer.append(name); initializer.append(")"); } field = newField(PRIVATE | STATIC | FINAL, TYPE_STRING, FIELD_NAME_$JAXX_OBJECT_DESCRIPTOR, false, initializer.toString() ); } } catch (IOException e) { throw new RuntimeException("Internal error: can't-happen error", e); } javaFile.addSimpleField(field); return field; } protected void addPreviousValuesField(JAXXCompiler compiler, JavaFile javaFile, CompiledObject root) { boolean superclassIsJAXXObject = javaFile.isSuperclassIsJAXXObject(); if (compiler.getStylesheet() != null) { boolean needField = true; if (superclassIsJAXXObject) { // check alreay exists on parent ClassDescriptor superclass = root.getObjectClass(); if (log.isDebugEnabled()) { log.debug("superclass : " + superclass); } JAXXCompiler parentCompiler = compiler.getEngine().getJAXXCompiler( superclass.getName() ); if (parentCompiler != null) { needField = parentCompiler.getStylesheet() == null; } else { try { superclass.getDeclaredFieldDescriptor( PREVIOUS_VALUES_FIELD.getName()); needField = false; } catch (NoSuchFieldException ex) { // field not found } } if (needField && log.isDebugEnabled()) { log.debug("no " + PREVIOUS_VALUES_FIELD.getName() + " field in super class"); } } if (needField) { addSimpleField(javaFile, PREVIOUS_VALUES_FIELD); } } } /*---------------------------------------------------------------------------------*/ /*-- Create methods ---------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/ protected void addPropertyChangeSupport(CompiledObject root, JavaFile javaFile) { ClassDescriptor currentClass = root.getObjectClass(); MethodDescriptor firePropertyChange = null; while (firePropertyChange == null && currentClass != null) { try { firePropertyChange = currentClass.getDeclaredMethodDescriptor( METHOD_NAME_FIRE_PROPERTY_CHANGE, ClassDescriptorHelper.getClassDescriptor(String.class), ClassDescriptorHelper.getClassDescriptor(Object.class), ClassDescriptorHelper.getClassDescriptor(Object.class) ); } catch (NoSuchMethodException e) { currentClass = currentClass.getSuperclass(); } } int modifiers = firePropertyChange != null ? firePropertyChange.getModifiers() : 0; if (isPublic(modifiers)) { // we have all the support we need return; } if (isProtected(modifiers)) { // there is property change support but the firePropertyChange method is protected javaFile.addMethod(FIRE_PROPERTY_CHANGE_METHOD); } else { addField(javaFile, PROPERTY_CHANGE_SUPPORT_FIELD); addMethod(javaFile, GET_PROPERTY_CHANGE_SUPPORT_METHOD, PropertyChangeSupport.class.getName()); addMethod(javaFile, ADD_PROPERTY_CHANGE_SUPPORT_METHOD); addMethod(javaFile, ADD_PROPERTY_CHANGE_SUPPORT_NAMED_METHOD); addMethod(javaFile, REMOVE_PROPERTY_CHANGE_SUPPORT_METHOD); addMethod(javaFile, REMOVE_PROPERTY_CHANGE_SUPPORT_NAMED_METHOD); addMethod(javaFile, FIRE_PROPERTY_CHANGE_NAMED_METHOD); } } protected void addInitialize_01_createHandler(JAXXCompiler compiler, JavaFile javaFile, String className) { String handlerReturnType = String.format("%s", compiler.getImportedType(UIHandler.class.getName()), compiler.getImportedType(JAXXObject.class.getName())); if (compiler.isAbstractClass()) { // abstract class can not define handler // declare abstract method JavaMethod method = newMethod(PROTECTED | ABSTRACT, handlerReturnType, METHOD_NAME_$INITIALIZE_01_CREATE_HANDLER, "", javaFile.isSuperclassIsJAXXObject() ); javaFile.addMethod(method); return; } StringBuilder body = new StringBuilder(); body.append(JavaFileGenerator.addDebugLoggerInvocation(compiler, "this")); String eol = JAXXCompiler.getLineSeparator(); ClassDescriptor objectClass = compiler.getRootObject().getObjectClass(); // boolean useHandler = compiler.isUseHandler() && (!compiler.isAbstractClass() || compiler.getCompiledObject("handler") != null); boolean useHandler = compiler.isUseHandler(); if (javaFile.isSuperclassIsJAXXObject()) { if (!useHandler && objectClass.tryToGetFieldDescriptor("handler").isPresent()) { // found a handler in super class, nothing to generate return; // // just override it // String handlerReturnType = String.format("%s<%s>", compiler.getImportedType(UIHandler.class.getName()), objectClass.getSimpleName()); // body.append(String.format("return super.%s();", METHOD_NAME_$INITIALIZE_01_CREATE_HANDLER)).append(eol); // JavaMethod method = newMethod(PROTECTED, // handlerReturnType, // METHOD_NAME_$INITIALIZE_01_CREATE_HANDLER, // body.toString(), // javaFile.isSuperclassIsJAXXObject() // ); // javaFile.addMethod(method); // return true; } } if (!useHandler) { body.append("return null;").append(eol); JavaMethod method = newMethod(PROTECTED, handlerReturnType, METHOD_NAME_$INITIALIZE_01_CREATE_HANDLER, body.toString(), javaFile.isSuperclassIsJAXXObject() ); javaFile.addMethod(method); return; } String handler = compiler.getUiHandler(); String handlerType = compiler.getImportedType(handler); body.append("return handler = new ").append(handlerType); String genericType = compiler.getGenericType(); if (genericType != null) { body.append("<>"); if (!compiler.isAbstractClass()) { handlerReturnType = handlerType; } else { handlerReturnType = String.format("%s<%s<%s>>", compiler.getImportedType(UIHandler.class.getName()), className, genericType); } } String constructorParams = ""; try { ClassDescriptor classDescriptor = ClassDescriptorHelper.getClassDescriptor(handler); MethodDescriptor[] constructorDescriptors = classDescriptor.getConstructorDescriptors(); if (constructorDescriptors.length == 1 && constructorDescriptors[0].getParameterTypes().length == 1 && constructorDescriptors[0].getParameterTypes()[0] != null) { if (constructorDescriptors[0].getParameterTypes()[0].isAssignableFrom(objectClass) || javaFile.getName().equals(constructorDescriptors[0].getParameterTypes()[0].getName()) || constructorDescriptors[0].getParameterTypes()[0].isAssignableFrom(ClassDescriptorHelper.getClassDescriptor(JAXXObject.class))) { constructorParams = "this"; } } } catch (ClassNotFoundException e) { // silent } body.append("(").append(constructorParams).append(");").append(eol); JavaMethod method = newMethod(PROTECTED, handlerReturnType, METHOD_NAME_$INITIALIZE_01_CREATE_HANDLER, body.toString(), javaFile.isSuperclassIsJAXXObject() ); javaFile.addMethod(method); } protected void addInitialize_01_createComponents(JAXXCompiler compiler, JavaFile javaFile) { StringBuilder body = new StringBuilder(); body.append(JavaFileGenerator.addDebugLoggerInvocation(compiler, "this")); String eol = JAXXCompiler.getLineSeparator(); if (javaFile.isSuperclassIsJAXXObject()) { body.append(String.format("super.%s();", METHOD_NAME_$INITIALIZE_01_CREATE_COMPONENTS)).append(eol); } CompiledObject root = compiler.getRootObject(); String rootId = root.getId(); body.append(FIELD_NAME_$OBJECT_MAP + ".put(").append(TypeManager.getJavaCode(rootId)).append(", ").append(rootId).append(");").append(eol); Iterator i = compiler.getObjectCreationOrder(); boolean lastWasMethodCall = false; //TODO-TC20091025 should do init of root first ? // root.getDecorator().createInitializer(compiler, root, root, code, lastWasMethodCall); while (i.hasNext()) { CompiledObject object = i.next(); if (object == root) { continue; } CompiledObjectDecorator decorator = object.getDecorator(); lastWasMethodCall = decorator.createInitializer(compiler, root, object, body, lastWasMethodCall); } root.getDecorator().createInitializer(compiler, root, root, body, lastWasMethodCall); if (compiler.getInitializer().length() > 0) { body.append(compiler.getInitializer()); } JavaMethod method = newMethod(PROTECTED, TYPE_VOID, METHOD_NAME_$INITIALIZE_01_CREATE_COMPONENTS, body.toString(), javaFile.isSuperclassIsJAXXObject() ); javaFile.addMethod(method); } protected void addInitialize_02_registerDataBindings(JAXXCompiler compiler, JavaFile javaFile) { StringBuilder body = new StringBuilder(); body.append(JavaFileGenerator.addDebugLoggerInvocation(compiler, "this")); String eol = JAXXCompiler.getLineSeparator(); if (javaFile.isSuperclassIsJAXXObject()) { body.append(String.format("super.%s();", METHOD_NAME_$INITIALIZE_02_REGISTER_DATA_BINDINGS)).append(eol); } JavaFileGenerator generator = new JavaFileGenerator(eol, true); //TODO use optimized writer for simple cases for (JAXXBindingWriter writer : bindingWriters) { writer.reset(); } // add import on each type of JAXXBinding used for (JAXXBindingWriter writer : bindingWriters) { if (writer.isUsed()) { compiler.getJavaFile().addImport(writer.getType()); } } DataBinding[] bindings = compiler.getBindingHelper().getDataBindings(); body.append("// register "); body.append(bindings.length); body.append(" data bindings"); body.append(eol); for (DataBinding binding : bindings) { for (JAXXBindingWriter writer : bindingWriters) { if (writer.accept(binding)) { writer.write(binding, generator, body); break; } } } JavaMethod method = newMethod(PROTECTED, TYPE_VOID, METHOD_NAME_$INITIALIZE_02_REGISTER_DATA_BINDINGS, body.toString(), javaFile.isSuperclassIsJAXXObject() ); javaFile.addMethod(method); } protected void addInitialize_02_registerActions(JAXXCompiler compiler, JavaFile javaFile) { StringBuilder body = new StringBuilder(); body.append(JavaFileGenerator.addDebugLoggerInvocation(compiler, "this")); String eol = JAXXCompiler.getLineSeparator(); if (javaFile.isSuperclassIsJAXXObject()) { body.append(String.format("super.%s();", METHOD_NAME_$INITIALIZE_03_REGISTER_ACTIONS)).append(eol); } body.append(compiler.getActionsInitializer()).append(eol); JavaMethod method = newMethod(PROTECTED, TYPE_VOID, METHOD_NAME_$INITIALIZE_03_REGISTER_ACTIONS, body.toString(), javaFile.isSuperclassIsJAXXObject() ); javaFile.addMethod(method); } protected void addInitialize_03_finalizeCreateComponents(JAXXCompiler compiler, JavaFile javaFile) { StringBuilder body = new StringBuilder(); body.append(JavaFileGenerator.addDebugLoggerInvocation(compiler, "this")); String eol = JAXXCompiler.getLineSeparator(); if (javaFile.isSuperclassIsJAXXObject()) { body.append(String.format("super.%s();", METHOD_NAME_$INITIALIZE_03_FINALIZE_CREATE_COMPONENTS)).append(eol); } for (CompiledObject object : compiler.getObjects().values()) { CompiledObjectDecorator decorator = object.getDecorator(); body.append(decorator.createCompleteSetupMethod(compiler, object, javaFile) ); } JavaMethod method = newMethod(PROTECTED, TYPE_VOID, METHOD_NAME_$INITIALIZE_03_FINALIZE_CREATE_COMPONENTS, body.toString(), javaFile.isSuperclassIsJAXXObject() ); javaFile.addMethod(method); } protected void addInitialize_04_applyDataBindings(JAXXCompiler compiler, JavaFile javaFile) { StringBuilder body = new StringBuilder(); String eol = JAXXCompiler.getLineSeparator(); body.append(JavaFileGenerator.addDebugLoggerInvocation(compiler, "this")); if (javaFile.isSuperclassIsJAXXObject()) { body.append(String.format("super.%s();", METHOD_NAME_$INITIALIZE_04_APPLY_DATA_BINDINGS)).append(eol); } else { DataBinding[] bindings = compiler.getBindingHelper().getDataBindings(); if (bindings.length > 0) { body.append(eol); body.append("// apply "); body.append(bindings.length); body.append(" data bindings"); body.append(eol); body.append(JAXXUtil.class.getSimpleName()); body.append("." + METHOD_NAME_APPLY_DATA_BINDING + "(this, " + FIELD_NAME_$BINDINGS + ".keySet());"); body.append(eol); } } JavaMethod method = newMethod(PROTECTED, TYPE_VOID, METHOD_NAME_$INITIALIZE_04_APPLY_DATA_BINDINGS, body.toString(), javaFile.isSuperclassIsJAXXObject() ); javaFile.addMethod(method); } protected void addInitialize_05_setProperties(JAXXCompiler compiler, JavaFile javaFile) { StringBuilder body = new StringBuilder(); String eol = JAXXCompiler.getLineSeparator(); body.append(JavaFileGenerator.addDebugLoggerInvocation(compiler, "this")); if (javaFile.isSuperclassIsJAXXObject()) { body.append(String.format("super.%s();", METHOD_NAME_$INITIALIZE_05_SET_PROPERTIES)).append(eol); } DataBinding[] bindings = compiler.getBindingHelper().getSimpleBindings(); if (bindings.length > 0) { StringBuilder initCode = new StringBuilder(); for (DataBinding binding : bindings) { String binding1 = binding.getInitDataBinding(); if (binding1 != null && !binding1.trim().isEmpty()) { initCode.append(binding1); } } if (initCode.length() > 0) { body.append(eol); body.append("// apply "); body.append(bindings.length); body.append(" property setters"); body.append(eol); body.append(initCode.toString().trim()); } } if (compiler.getLateInitializer().length() > 0) { body.append("// late initializer").append(eol); body.append(compiler.getLateInitializer()).append(eol); } JavaMethod method = newMethod(PROTECTED, TYPE_VOID, METHOD_NAME_$INITIALIZE_05_SET_PROPERTIES, body.toString(), javaFile.isSuperclassIsJAXXObject() ); javaFile.addMethod(method); } protected void addInitialize_06_finalizeInitialize(JAXXCompiler compiler, JavaFile javaFile) { StringBuilder body = new StringBuilder(); body.append(JavaFileGenerator.addDebugLoggerInvocation(compiler, "this")); String eol = JAXXCompiler.getLineSeparator(); if (javaFile.isSuperclassIsJAXXObject()) { body.append(String.format("super.%s();", METHOD_NAME_$INITIALIZE_06_FINALIZE_INITIALIZE)).append(eol); } JavaMethod method = newMethod(PROTECTED, TYPE_VOID, METHOD_NAME_$INITIALIZE_06_FINALIZE_INITIALIZE, body.toString(), javaFile.isSuperclassIsJAXXObject() ); javaFile.addMethod(method); } protected void addEventHandlers(JAXXCompiler compiler, JavaFile javaFile) { for (Map.Entry>> e1 : compiler.getEventHandlers().entrySet()) { // outer loop is iterating over different objects (well, technically, different Java expressions) for (Map.Entry> e2 : e1.getValue().entrySet()) { // iterate over different types of listeners for this particular object (MouseListener, ComponentListener, etc.) for (EventHandler handler : e2.getValue()) { // iterate over individual event handlers of a single type String methodName = compiler.getEventHandlerMethodName(handler); MethodDescriptor listenerMethod = handler.getListenerMethod(); if (listenerMethod.getParameterTypes().length != 1) { throw new CompilerException( "Expected event handler " + listenerMethod.getName() + " of class " + handler.getListenerClass() + " to have exactly one argument" ); } ClassDescriptor eventType = listenerMethod.getParameterTypes()[0]; JavaArgument argument = JavaElementFactory.newArgument( JAXXCompiler.getCanonicalName(eventType), "event" ); String body = JavaFileGenerator.addDebugLoggerInvocation(compiler, "event"); body += handler.getJavaCode(); javaFile.addMethod(JavaElementFactory.newMethod( PUBLIC, TYPE_VOID, methodName, body, false, argument) ); } } } } public void addInitializerMethod(JAXXCompiler compiler, JavaFile javaFile) { String eol = JAXXCompiler.getLineSeparator(); StringBuilder code = new StringBuilder(); code.append(JavaFileGenerator.addDebugLoggerInvocation(compiler, "this")); code.append(compiler.getRootObject().getId()).append(" = this;").append(eol); if (javaFile.isSuperclassIsJAXXObject()) { code.append("super." + METHOD_NAME_$INITIALIZE + "();").append(eol); } else { code.append(String.format(METHOD_$INITIALIZER_CALL, eol, METHOD_NAME_$INITIALIZE_01_CREATE_HANDLER, METHOD_NAME_$INITIALIZE_01_CREATE_COMPONENTS, METHOD_NAME_$INITIALIZE_02_REGISTER_DATA_BINDINGS, METHOD_NAME_$INITIALIZE_03_FINALIZE_CREATE_COMPONENTS, METHOD_NAME_$INITIALIZE_03_REGISTER_ACTIONS, METHOD_NAME_$INITIALIZE_04_APPLY_DATA_BINDINGS, METHOD_NAME_$INITIALIZE_05_SET_PROPERTIES, METHOD_NAME_$INITIALIZE_06_FINALIZE_INITIALIZE )); } JavaMethod method = JavaElementFactory.newMethod(PROTECTED, TYPE_VOID, METHOD_NAME_$INITIALIZE, code.toString(), javaFile.isSuperclassIsJAXXObject() ); javaFile.addMethod(method); } protected JavaMethod createApplyDataBindingMethod() { StringBuilder buffer = new StringBuilder(); String eol = JAXXCompiler.getLineSeparator(); buffer.append("if (" + FIELD_NAME_$BINDINGS + ".containsKey(" + PARAMETER_NAME_$BINDING + ")) {"); buffer.append(eol); buffer.append(" getDataBinding(" + PARAMETER_NAME_$BINDING + ")." + METHOD_NAME_APPLY_DATA_BINDING + "();"); buffer.append(eol); buffer.append("}"); buffer.append(eol); buffer.append(METHOD_NAME_PROCESS_DATA_BINDING + "(" + PARAMETER_NAME_$BINDING + ");"); return JavaElementFactory.newMethod( PUBLIC, TYPE_VOID, METHOD_NAME_APPLY_DATA_BINDING, buffer.toString(), true, JavaElementFactory.newArgument(TYPE_STRING, PARAMETER_NAME_$BINDING) ); } protected JavaMethod createRemoveDataBindingMethod() { StringBuilder buffer = new StringBuilder(); String eol = JAXXCompiler.getLineSeparator(); buffer.append("if (" + FIELD_NAME_$BINDINGS + ".containsKey(" + PARAMETER_NAME_$BINDING + ")) {"); buffer.append(eol); buffer.append(" getDataBinding(" + PARAMETER_NAME_$BINDING + ")." + METHOD_NAME_REMOVE_DATA_BINDING + "();"); buffer.append(eol); buffer.append("}"); return JavaElementFactory.newMethod( PUBLIC, TYPE_VOID, METHOD_NAME_REMOVE_DATA_BINDING, buffer.toString(), true, JavaElementFactory.newArgument(TYPE_STRING, PARAMETER_NAME_$BINDING) ); } protected JavaMethod createProcessDataBindingMethod() { StringBuilder code = new StringBuilder(); String eol = JAXXCompiler.getLineSeparator(); // the force parameter forces the update to happen even if it is already in activeBindings. This // is used on superclass invocations b/c by the time the call gets to the superclass, it is already // marked active and would otherwise be skipped code.append(" if (!$force && " + FIELD_NAME_$ACTIVE_BINDINGS + ".contains(" + PARAMETER_NAME_$BINDING + ")) { "); code.append(eol); code.append(" return;"); code.append(eol); code.append("}").append(eol); code.append(FIELD_NAME_$ACTIVE_BINDINGS + ".add(" + PARAMETER_NAME_$BINDING + ");"); code.append(eol); code.append("try {").append(eol); code.append(" if (" + FIELD_NAME_$BINDINGS + ".containsKey(" + PARAMETER_NAME_$BINDING + ")) {"); code.append(eol); code.append(" getDataBinding(" + PARAMETER_NAME_$BINDING + ")." + METHOD_NAME_PROCESS_DATA_BINDING + "();"); code.append(eol); code.append(" }").append(eol); code.append("} finally {").append(eol); code.append(" " + FIELD_NAME_$ACTIVE_BINDINGS + ".remove(" + PARAMETER_NAME_$BINDING + ");"); code.append(eol); code.append("}").append(eol); return JavaElementFactory.newMethod( PUBLIC, TYPE_VOID, METHOD_NAME_PROCESS_DATA_BINDING, code.toString(), true, newArgument(TYPE_STRING, PARAMETER_NAME_$BINDING), newArgument(TYPE_BOOLEAN, "$force") ); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy