0 Replies Latest reply on Apr 18, 2013 9:27 PM by Carsten Jäger

    "duplicate class definition" error on CtClass.toClass() call

    Carsten Jäger Newbie

      I'm trying to reflect annotation changes to classes.

       

      When i call the CtClass.toClass() method i'm always getting the following error:

      javassist.CannotCompileException: by java.lang.LinkageError: loader (instance of  sun/misc/Launcher$AppClassLoader): attempted  duplicate class definition for name: "ReflectionTest"

       

      Googl'ing for a solution, told me to provide an own ClassLoader when calling the toClass() method. But i found no sample how to implement it...

       

      This is my Testcase:

       

      1.) The class to modify:


      import javax.persistence.Table;

       

      @Table(name="xyz")

      public class ReflectionTest {

      }

       

      2.) The test class:

       

      import java.util.ArrayList;

      import java.util.Collection;

      import javassist.ClassPool;

      import javassist.CtClass;

      import javassist.bytecode.AnnotationsAttribute;

      import javassist.bytecode.ConstPool;

      import javassist.bytecode.annotation.Annotation;

      import javassist.bytecode.annotation.StringMemberValue;

      import javax.persistence.Table;

       

      public class ReflectionSample {

       

          public static void main(final String[] args) {

              /*

               * It's no solution to provide just the class names as a string,

               * what will only work, if no application part accessed the classes already.

               */

              final Collection<Class<?>> classes = new ArrayList<Class<?>>();

              classes.add(ReflectionTest.class);

              doReflection(classes);

       

              final ReflectionTest test = new ReflectionTest();

              final Table table = test.getClass().getAnnotation(Table.class);

       

              System.out.println("name  : " + table.name());   // Expecting: "xyz"

              System.out.println("schema: " + table.schema()); // Expecting: "TestSchema"

          }


          private static void doReflection(final Collection<Class<?>> classes) {

              final ClassPool classPool = ClassPool.getDefault();

              for (final Class<?> clazz : classes) {

                  try {

                      final CtClass ctClass = classPool.get(clazz.getName());

                      final ConstPool constPool = ctClass.getClassFile().getConstPool();

                      final AnnotationsAttribute attribute = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);

                      final Table table = (Table) ctClass.getAnnotation(Table.class);

                      final Annotation tableAnnotation = new Annotation("javax.persistence.Table", constPool);

                      tableAnnotation.addMemberValue("name", new StringMemberValue(table.name(), constPool));

                      tableAnnotation.addMemberValue("schema", new StringMemberValue("TestSchema", constPool));

                      attribute.addAnnotation(tableAnnotation);

                      ctClass.getClassFile().addAttribute(attribute);

                      // This throws a java.lang.LinkageError ... attempted  duplicate class definition for name: "ReflectionTest"!

                      ctClass.toClass();

                  } catch (Exception e) {

                      e.printStackTrace();

                  }

              }

          }

      }

       

       

      Any help is appreciated!

       

      Tia, Carsten


       

      P.S.: See attached ZIP for the source files...