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

jaxx.compiler.tasks.GenerateConstructorsTask Maven / Gradle / Ivy

There is a newer version: 3.0-alpha-6
Show newest version
/*
 * #%L
 * JAXX :: Compiler
 * 
 * $Id: GenerateConstructorsTask.java 2243 2011-03-18 11:19:23Z tchemit $
 * $HeadURL: http://svn.nuiton.org/svn/jaxx/tags/jaxx-2.5.27/jaxx-compiler/src/main/java/jaxx/compiler/tasks/GenerateConstructorsTask.java $
 * %%
 * Copyright (C) 2008 - 2010 CodeLutin
 * %%
 * 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 jaxx.compiler.tasks;

import jaxx.compiler.CompiledObject;
import jaxx.compiler.CompilerException;
import jaxx.compiler.JAXXCompiler;
import jaxx.compiler.JAXXCompilerFile;
import jaxx.compiler.JAXXEngine;
import jaxx.compiler.finalizers.DefaultFinalizer;
import jaxx.compiler.java.JavaArgument;
import jaxx.compiler.java.JavaConstructor;
import jaxx.compiler.java.JavaElementFactory;
import jaxx.compiler.java.JavaFile;
import jaxx.compiler.reflect.ClassDescriptor;
import jaxx.compiler.reflect.ClassDescriptorHelper;
import jaxx.compiler.reflect.MethodDescriptor;
import jaxx.compiler.tags.TagManager;
import jaxx.runtime.JAXXContext;
import jaxx.runtime.JAXXUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import static java.lang.reflect.Modifier.PUBLIC;

/**
 * Task to execute just after finalize task to create all constructors for any
 * compiler.
 * 

* In fact, we can not compute constructor in one time since some compiler may * need of the constructors of previous compiler... *

* This task will compute all constructors to generate. * * @author tchemit * @see JavaConstructor * @since 2.4 */ public class GenerateConstructorsTask extends JAXXEngineTask { /** Logger */ private static final Log log = LogFactory.getLog(GenerateConstructorsTask.class); /** Task name */ public static final String TASK_NAME = "PostFinalize"; private static final String PARAMETER_NAME_PARENT_CONTEXT = "parentContext"; public GenerateConstructorsTask() { super(TASK_NAME); } @Override public boolean perform(JAXXEngine engine) throws Exception { boolean success = true; boolean isVerbose = engine.getConfiguration().isVerbose(); JAXXCompilerFile[] files = engine.getCompiledFiles(); // to contains all compilers List compilers = new ArrayList(); for (JAXXCompilerFile jaxxFile : files) { compilers.add(jaxxFile.getCompiler()); } int round = 0; while (!compilers.isEmpty()) { if (isVerbose) { log.info("Round " + round++ + ", still " + compilers.size() + " compilers to treat."); } // launch a round since there is still some compiler to treat Iterator itr = compilers.iterator(); while (itr.hasNext()) { JAXXCompiler compiler = itr.next(); JavaFile javaFile = compiler.getJavaFile(); boolean isJAXXObject = javaFile.isSuperclassIsJAXXObject(); if (!isJAXXObject) { // can directly compute constructors if (log.isDebugEnabled()) { log.debug("Compute constructor from non super " + "jaxx object file " + javaFile.getName()); } // get the constructors of the parent class addConstructorsForNoneSuperClassJaxx(engine, compiler); itr.remove(); continue; } // compiler inheritate from a jaxx object CompiledObject rootObject = compiler.getRootObject(); ClassDescriptor parentClassDescriptor = rootObject.getObjectClass(); if (parentClassDescriptor.getResolverType() != ClassDescriptorHelper.ResolverType.JAXX_FILE) { // the parent was not generated by this engine; we can safely // use it if (log.isDebugEnabled()) { log.debug("Compute constructor from outside super " + "jaxx object file " + javaFile.getName()); } addConstructorsForSuperClassJaxx(engine, compiler, null); itr.remove(); continue; } JAXXCompiler parentCompiler = engine.getJAXXCompiler( JAXXCompiler.getCanonicalName(parentClassDescriptor)); if (!compilers.contains(parentCompiler)) { // parent was generated by this engine and was laready // treated, can now safely deal this the given compiler if (log.isDebugEnabled()) { log.debug("Compute constructor from inside super " + "jaxx object file " + javaFile.getName()); } addConstructorsForSuperClassJaxx(engine, compiler, parentCompiler); itr.remove(); continue; } // can not treate at the moment... if (log.isDebugEnabled()) { log.debug("Can not compute constructors for " + compiler.getRootObject().getId() + " waits fro his parent to be treated..."); } } } return success; } /** * To add constructor on the given {@code compiler}, knowing that the super * class of it is not a jaxx class. *

* In this mode, we takes all the constructors of the parent (if parent has * some!) and for each of them add the simple one and another one with * first parameter a {@link JAXXContext}. * * @param engine the current engine which compiled compiler * @param compiler the current compiler to treat * @throws ClassNotFoundException if a class could not be found (when wanted to have extact type for constructor parameters) * @throws IllegalStateException if given {@code compiler has a super JAXX class}. */ protected void addConstructorsForNoneSuperClassJaxx(JAXXEngine engine, JAXXCompiler compiler) throws ClassNotFoundException, IllegalStateException { JavaFile javaFile = compiler.getJavaFile(); if (javaFile.isSuperclassIsJAXXObject()) { throw new IllegalStateException( "This method does not accept compiler that " + "inheritates from a jaxx file."); } String className = javaFile.getSimpleName(); if (engine.isVerbose()) { log.info("start " + javaFile.getName()); } addStartProfileTime(engine, compiler); // get already registred constructors : need to keep the list of parameters // not to generate a constructor with same prototype twice. List> prototypes = getDeclaredConstructorPrototypes(compiler, javaFile); MethodDescriptor[] constructorDescriptors = compiler.getRootObject().getObjectClass().getConstructorDescriptors(); List constructorTypes; boolean canAddConstructor; if (constructorDescriptors == null || constructorDescriptors.length == 0) { // no constructors (use only a default constructor) constructorTypes = getConstructorTypes(); canAddConstructor = canAddConstructor(prototypes, constructorTypes); if (canAddConstructor) { addConstructor(compiler, className, constructorTypes); } constructorTypes.add(0, JAXXCompiler.getCanonicalName(JAXXContext.class)); canAddConstructor = canAddConstructor(prototypes, constructorTypes); if (canAddConstructor) { addConstructorWithInitialContext(compiler, className, constructorTypes, false); } } else { for (MethodDescriptor constructorDescriptor : constructorDescriptors) { constructorTypes = getConstructorTypes(constructorDescriptor.getParameterTypes()); canAddConstructor = canAddConstructor(prototypes, constructorTypes); if (canAddConstructor) { addConstructor(compiler, className, constructorTypes); } constructorTypes.add(0, JAXXCompiler.getCanonicalName(JAXXContext.class)); canAddConstructor = canAddConstructor(prototypes, constructorTypes); if (canAddConstructor) { addConstructorWithInitialContext(compiler, className, constructorTypes, false); } } } addEndProfileTime(engine, compiler); } /** * To add constructor on the given {@code compiler}, knowing that the super * class of it is a jaxx class. *

* In this mode, we takes all the constructors of the parent (if parent has * some!) and for each of them add the simple one and another one with * first parameter a {@link JAXXContext}. * * @param engine the current engine which compiled compiler * @param compiler the current compiler to treat * @param parentCompiler the compiler of the super class (can be * {@code null} if super class was not generated by * the given engine). * @throws ClassNotFoundException if a class could not be found (when wanted to have extact type for constructor parameters) * @throws IllegalStateException if given {@code compiler has not a super JAXX class}. */ protected void addConstructorsForSuperClassJaxx(JAXXEngine engine, JAXXCompiler compiler, JAXXCompiler parentCompiler) throws ClassNotFoundException, IllegalStateException { JavaFile javaFile = compiler.getJavaFile(); if (!javaFile.isSuperclassIsJAXXObject()) { throw new IllegalStateException( "This method does not accept compiler that " + "inheritates not from a jaxx file."); } String className = javaFile.getSimpleName(); if (engine.isVerbose()) { log.info("start " + javaFile.getName()); } addStartProfileTime(engine, compiler); // get already registred constructors : need to keep the list of parameters // not to generate a constructor with same prototype twice. List> prototypes = getDeclaredConstructorPrototypes(compiler, javaFile); MethodDescriptor[] constructorDescriptors; if (parentCompiler == null) { // the parent was not generated by this engine, this means that is // class descriptor can be used to obtain constructors constructorDescriptors = compiler.getRootObject().getObjectClass().getConstructorDescriptors(); } else { // the parent was generated by this engine, can not trust the class // descriptor at the moment, so just seek in his java file for // already generated constructor List constructors = parentCompiler.getJavaFile().getConstructors(); constructorDescriptors = new MethodDescriptor[constructors.size()]; int i = 0; for (JavaConstructor constructor : constructors) { String[] parameters = new String[constructor.getArguments().length]; int j = 0; for (JavaArgument argument : constructor.getArguments()) { String type = argument.getType(); parameters[j++] = type; } constructorDescriptors[i++] = new MethodDescriptor( null, constructor.getModifiers(), null, parameters, compiler.getClassLoader() ); } } // dealing with a jsuper class JAXX we are sure to have at least two constructors : // a default one + one with just a JAXXContext parameter List constructorTypes; boolean canAddConstructor; for (MethodDescriptor constructorDescriptor : constructorDescriptors) { ClassDescriptor[] parameterTypes = constructorDescriptor.getParameterTypes(); if (parentCompiler == null) { // we already have the good type ??? this is dangerous // because we could miss an import ? must be improved constructorTypes = new ArrayList(parameterTypes.length); for (ClassDescriptor parameterType : parameterTypes) { constructorTypes.add(parameterType.getName()); } } else { constructorTypes = getConstructorTypes(parameterTypes); } canAddConstructor = canAddConstructor(prototypes, constructorTypes); if (canAddConstructor) { addConstructor(compiler, className, constructorTypes); } // constructorTypes.add(0, JAXXCompiler.getCanonicalName(JAXXContext.class)); // canAddConstructor = canAddConstructor(prototypes, constructorTypes); // if (canAddConstructor) { // addConstructorWithInitialContext(compiler, className, constructorTypes, true); // } } addEndProfileTime(engine, compiler); } protected List> getDeclaredConstructorPrototypes(JAXXCompiler compiler, JavaFile javaFile) throws ClassNotFoundException { List constructors = javaFile.getConstructors(); List> prototypes = new ArrayList>(constructors.size()); for (JavaConstructor constructor : constructors) { List prototype = new ArrayList(); for (JavaArgument argument : constructor.getArguments()) { String type = argument.getType(); String fqn = TagManager.resolveClassName(type, compiler); ClassDescriptor classDescriptor = ClassDescriptorHelper.getClassDescriptor(fqn); String canonicalName = JAXXCompiler.getCanonicalName(classDescriptor); prototype.add(canonicalName); } prototypes.add(prototype); } return prototypes; } private boolean canAddConstructor(List> prototypes, List constructorTypes) { return !prototypes.contains(constructorTypes); } private List getConstructorTypes(ClassDescriptor... descriptors) { List result = new ArrayList(); // add all parameters from constructor for (ClassDescriptor descriptor : descriptors) { String fqn = JAXXCompiler.getCanonicalName(descriptor); result.add(fqn); } return result; } protected void addConstructor(JAXXCompiler compiler, String className, List constructorTypes) throws CompilerException { StringBuilder code = new StringBuilder(); String eol = JAXXCompiler.getLineSeparator(); JavaArgument[] arguments = new JavaArgument[constructorTypes.size()]; if (!constructorTypes.isEmpty()) { // constructeur avec des paramètres code.append(" super("); int i = 0; for (String constructorType : constructorTypes) { JavaArgument argument = JavaElementFactory.newArgument( constructorType, "param" + i ); arguments[i] = argument; if (i > 0) { code.append(" ,"); } code.append(argument.getName()); i++; } code.append(");").append(eol); } code.append(DefaultFinalizer.METHOD_NAME_$INITIALIZE + "();"); code.append(eol); JavaConstructor constructor = JavaElementFactory.newConstructor(PUBLIC, className, code.toString(), arguments ); compiler.getJavaFile().addConstructor(constructor); } protected void addConstructorWithInitialContext(JAXXCompiler compiler, String className, List constructorTypes, boolean superclassIsJAXXObject) throws CompilerException { StringBuilder code = new StringBuilder(); String eol = JAXXCompiler.getLineSeparator(); JavaArgument firstArgument = JavaElementFactory.newArgument( JAXXContext.class.getName(), PARAMETER_NAME_PARENT_CONTEXT ); JavaArgument[] arguments = new JavaArgument[constructorTypes.size()]; arguments[0] = firstArgument; for (int i = 1, max = constructorTypes.size(); i < max; i++) { String constructorType = constructorTypes.get(i); JavaArgument argument = JavaElementFactory.newArgument( constructorType, "param" + i ); arguments[i] = argument; } if (superclassIsJAXXObject) { // we are sure to have at least the first parameter in the super code code.append(" super("); code.append(PARAMETER_NAME_PARENT_CONTEXT); for (int i = 1, max = constructorTypes.size(); i < max; i++) { String constructorType = constructorTypes.get(i); JavaArgument argument = JavaElementFactory.newArgument( constructorType, "param" + i ); arguments[i] = argument; code.append(" ,"); code.append(argument.getName()); } code.append(");").append(eol); } else { // only a super class only if more than the parentContext parameter if (constructorTypes.size() > 1) { code.append(" super("); for (int i = 1, max = constructorTypes.size(); i < max; i++) { String constructorType = constructorTypes.get(i); JavaArgument argument = JavaElementFactory.newArgument( constructorType, "param" + i ); arguments[i] = argument; if (i > 1) { code.append(" ,"); } code.append(argument.getName()); } code.append(");").append(eol); } } if (!superclassIsJAXXObject) { // call explicitly the init code of the parentContext String prefix = compiler.getImportedType(JAXXUtil.class); code.append(prefix); code.append(".initContext(this, " + PARAMETER_NAME_PARENT_CONTEXT + ");"); code.append(eol); } code.append(DefaultFinalizer.METHOD_NAME_$INITIALIZE + "();"); code.append(eol); JavaConstructor constructor = JavaElementFactory.newConstructor(PUBLIC, className, code.toString(), arguments ); compiler.getJavaFile().addConstructor(constructor); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy