3 Replies Latest reply on Feb 19, 2007 3:54 PM by rbodkin

    generics

    bblfish

      I noticed in the documentation that there is no support for generics in page 2 of the tutorial. This should not be surprising due to the lack of information remaining in the bytecode about the generic nature of an object.

      I was hoping to be able to take code such as

      class MyClass {
       @RDF(foaf+"knows") Collection<Person> person;
      
       ....
      }
      

      and be able to deduce that the variable person should only contain Person objects. Is there any way around that?


        • 1. Re: generics
          bblfish

          From this IBM article Classworking toolkit: Reflecting generics it should be possible to find out more information about the generic types of fields, as some of this information is stored in the bytecode. Would it not be possible to extend some of the Ctxxx classes to provide this information?

          (Though I may be misreading this article)

          • 2. Re: generics
            bblfish

            Using the IBM article mentioned above I was able to get my code to go quite a long way using introspection. It may still be useful to have better access to this via the javassist api, as that would remove the need for introspection. I'll report further on any problems I come across...

            package com.sun.labs.rdf.sommer;
            
            import com.sun.labs.rdf.annotations.RDF;
            import javassist.*;
            import javassist.expr.ExprEditor;
            import javassist.expr.FieldAccess;
            
            import java.lang.reflect.ParameterizedType;
            import java.lang.reflect.Type;
            import java.lang.reflect.TypeVariable;
            
            /**
             * @author Henry Story
             */
            public class ClassRewriter {
            
             public static String reverse(String value) {
             int length = value.length();
             StringBuffer buff = new StringBuffer(length);
             for (int i = length - 1; i >= 0; i--) {
             buff.append(value.charAt(i));
             }
             System.out.println("TranslateEditor.reverse returning " + buff);
             return buff.toString();
             }
            
             public static Object setField(Type gtype, Class c, Object o, String url, Object value) {
             if (gtype instanceof ParameterizedType) {
            
             // list the raw type information
             ParameterizedType ptype = (ParameterizedType) gtype;
             Type rtype = ptype.getRawType();
             System.out.println("rawType is instance of " +
             rtype.getClass().getName());
             System.out.println(" (" + rtype + ")");
            
             // list the actual type arguments
             Type[] targs = ptype.getActualTypeArguments();
             System.out.println("actual type arguments are:");
             for (int j = 0; j < targs.length; j++) {
             System.out.println(" instance of " +
             targs[j].getClass().getName() + ":");
             System.out.println(" (" + targs[j] + ")");
             }
             } else {
             System.out.println
             ("getGenericType is not a ParameterizedType!");
             }
             if (c.getTypeParameters().length > 0) {
             System.out.println(c + "has " + c.getTypeParameters().length + " type parameters");
             for (TypeVariable tv : c.getTypeParameters()) {
             System.out.println("t.name=" + tv.getName() + " t.gd=" + tv.getGenericDeclaration());
             }
             }
             System.out.println("class=" + c + " setting o=" + o + " R=" + url + " v=" + value);
             return value;
             }
            
            
             public static void getField(Class c, Object o, String url, Object value) {
             System.out.println("class=" + c + " getting o=" + o + " R=" + url + " v=" + value);
             }
            
            
             public static void main(String[] args) {
             if (args.length != 0) {
             try {
             // set up class loader with translator
             EditorTranslator xtor = new EditorTranslator(new FieldSetEditor());
             ClassPool pool = ClassPool.getDefault();
             Loader loader = new Loader();
             loader.addTranslator(pool, xtor);
            
             // invoke the "main" method of the application class
            
             loader.run(args);
             } catch (Throwable ex) {
             ex.printStackTrace();
             }
             } else {
             System.out.println("Usage: ClassRewriter main-class args...");
             }
             }
            
            
            }
            
            class EditorTranslator implements Translator {
             private ExprEditor m_editor;
            
             EditorTranslator(ExprEditor editor) {
             m_editor = editor;
             }
            
             public void start(ClassPool pool) {
             System.out.println("start pool");
             }
            
            
             public void onLoad(ClassPool pool, String cname)
             throws NotFoundException, CannotCompileException {
             System.out.println("cname(in Onload)=" + cname);
             CtClass clas = pool.get(cname);
             clas.instrument(m_editor);
             }
            }
            
            class FieldSetEditor extends ExprEditor {
            
             FieldSetEditor() {
             }
            
             public void edit(FieldAccess arg) throws CannotCompileException {
             System.out.println("in edit- field=" + arg.getFieldName());
             try {
             String field;
             if ((field = containsRDF(arg.getField().getAnnotations())) != null) {
             if (arg.isWriter()) {
             StringBuffer code = new StringBuffer();
             code.append("$0.");
             code.append(arg.getFieldName());
            // code.append("=com.sun.labs.rdf.sommer.ClassRewriter.reverse($1);");
             code.append("=(" + arg.getField().getType().getName() + ")" +
             "com.sun.labs.rdf.sommer.ClassRewriter.setField("
             + "$class.getDeclaredField(\""+arg.getFieldName()+"\").getGenericType(),"
             + "$type,$0,\"" + field + "\",$1);");
             System.out.println("code=" + code.toString());
             System.out.println("type=" + arg.getField().getType().getName());
             arg.replace(code.toString());
             } else if (arg.isReader()) {
             StringBuffer code = new StringBuffer();
             code.append("com.sun.labs.rdf.sommer.ClassRewriter.getField($type, $0,\"" + field + "\"," + arg.getFieldName() + ");");
             code.append("$_ = ($r)" + arg.getFieldName() + ";");
             System.out.println("code=" + code.toString());
             arg.replace(code.toString());
            
             }
             }
            
             } catch (ClassNotFoundException e) {
             e.printStackTrace(); //todo: decide what exception to throw
             } catch (NotFoundException e) {
             e.printStackTrace(); //todo: decide what exception to throw
             }
             }
            
             private String containsRDF(Object[] annotations) {
             for (Object o : annotations) {
             if (o instanceof RDF) return ((RDF) o).value();
             }
             return null;
             }
            }
            


            • 3. Re: generics
              rbodkin

              Likewise, I'm curious about whether it would be possible to let Javassist accept Java 5 code forms like boxing and unboxing and handling of generics correctly in code snippets in source. For example, I tried to extend
              abstract class Holder {
              T get();
              }

              I have to implement that with casts and Object get(); to work and I can't, for example, return an int and have it boxed to be an Integer as I could in Java 5 source.

              Is there any plan to extend Javassist in this way?