/* * This code is distributed under The GNU Lesser General Public License (LGPLv3) * Please visit GNU site for LGPLv3 http://www.gnu.org/copyleft/lesser.html * * Copyright Denis Pavlov 2009 * Web: http://www.genericdtoassembler.org * SVN: https://svn.code.sf.net/p/geda-genericdto/code/trunk/ * SVN (mirror): http://geda-genericdto.googlecode.com/svn/trunk/ */ package com.inspiresoftware.lib.dto.geda.assembler.extension.impl; import com.inspiresoftware.lib.dto.geda.assembler.extension.DataReader; import com.inspiresoftware.lib.dto.geda.assembler.extension.DataWriter; import com.inspiresoftware.lib.dto.geda.assembler.extension.MethodSynthesizer; import com.inspiresoftware.lib.dto.geda.exception.GeDARuntimeException; import com.inspiresoftware.lib.dto.geda.exception.UnableToCreateInstanceException; import javassist.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Method; import java.lang.reflect.Type; /** * Javassist implementation. * * @author DPavlov * @since 1.1.0 */ public class JavassistMethodSynthesizer extends AbstractPlainTextMethodSynthesizer implements MethodSynthesizer { private static final Logger LOG = LoggerFactory.getLogger(JavassistMethodSynthesizer.class); private ClassPool pool = new ClassPool(true); /** * Default constructor that adds GeDA path to pool for generating files. * * @param classLoader class loader */ public JavassistMethodSynthesizer(final ClassLoader classLoader) { super(classLoader); appendClassPath(pool); } /** * Hook for javassist pool classpath alterations. * * @param pool this synthesizer's pool */ protected void appendClassPath(final ClassPool pool) { pool.appendClassPath(new LoaderClassPath(getClassLoader())); } /** * Access to javassist pool for sub classes. * * @return this synthesizer's pool */ protected ClassPool getClassPool() { return pool; } /** {@inheritDoc} */ @Override protected String getSynthesizerId() { return "javassist"; } /** {@inheritDoc} */ protected DataReader makeReaderClass( final ClassLoader loader, final Method readMethod, final String readerClassName, final String sourceClassNameFull, final String sourceClassGetterMethodName, final Type sourceClassGetterMethodReturnType, final MakeContext ctx) throws UnableToCreateInstanceException, GeDARuntimeException { final CtClass ctClass = pool.makeClass(readerClassName); final StringBuilder readMethodCode = new StringBuilder(); final StringBuilder getReturnTypeMethodCode = new StringBuilder(); try { ctClass.setInterfaces(new CtClass[] { pool.get(DataReader.class.getCanonicalName()) }); generateReaderMethods(readMethodCode, getReturnTypeMethodCode, readerClassName, sourceClassNameFull, sourceClassGetterMethodName, sourceClassGetterMethodReturnType); CtMethod methodRead = CtMethod.make(readMethodCode.toString(), ctClass); ctClass.addMethod(methodRead); CtMethod methodGetReturnType = CtMethod.make(getReturnTypeMethodCode.toString(), ctClass); ctClass.addMethod(methodGetReturnType); ctClass.detach(); final DataReader reader = (DataReader) ctClass.toClass( loader, DataReader.class.getProtectionDomain()).newInstance(); return reader; } catch (CannotCompileException cce) { ctx.next(cce, readMethodCode.toString() + "\n\n" + getReturnTypeMethodCode.toString()); LOG.warn("Unable to create method in class: {}... possibly class already loaded", readerClassName); return null; } catch (Exception ite) { throw new UnableToCreateInstanceException(readerClassName, "Unable to instantiate class: " + readerClassName, ite); } } /** {@inheritDoc} */ protected DataWriter makeWriterClass( final ClassLoader loader, final Method writeMethod, final String writerClassName, final String sourceClassNameFull, final String sourceClassSetterMethodName, final Class< ? > sourceClassSetterMethodArgumentClass, final MakeContext ctx) throws UnableToCreateInstanceException { final CtClass ctClass = pool.makeClass(writerClassName); final StringBuilder writeMethodCode = new StringBuilder(); final StringBuilder getParameterTypeMethodCode = new StringBuilder(); try { ctClass.setInterfaces(new CtClass[] { pool.get(DataWriter.class.getCanonicalName()) }); generateWriterMethods(writeMethodCode, getParameterTypeMethodCode, writerClassName, sourceClassNameFull, sourceClassSetterMethodName, sourceClassSetterMethodArgumentClass); CtMethod methodWrite = CtMethod.make(writeMethodCode.toString(), ctClass); ctClass.addMethod(methodWrite); CtMethod methodGetParameterType = CtMethod.make(getParameterTypeMethodCode.toString(), ctClass); ctClass.addMethod(methodGetParameterType); ctClass.detach(); final DataWriter writer = (DataWriter) ctClass.toClass( loader, DataWriter.class.getProtectionDomain()).newInstance(); return writer; } catch (CannotCompileException cce) { ctx.next(cce, writeMethodCode.toString() + "\n\n" + getParameterTypeMethodCode.toString()); LOG.warn("Unable to create method in class: {}... possibly class had been loaded", writerClassName); return null; } catch (Exception ite) { throw new UnableToCreateInstanceException(writerClassName, "Unable to instantiate class: " + writerClassName, ite); } } /** {@inheritDoc} */ public void releaseResources() { super.releaseResources(); pool = null; } }