View Javadoc

1   package it.imolinfo.jbi4corba.webservice.generator.typedef;
2   
3   import it.imolinfo.jbi4corba.Logger;
4   import it.imolinfo.jbi4corba.LoggerFactory;
5   import it.imolinfo.jbi4corba.exception.ClassGenerationException;
6   import it.imolinfo.jbi4corba.webservice.generator.Util;
7   
8   import java.io.File;
9   import java.io.PrintWriter;
10  import java.io.StringWriter;
11  import java.lang.reflect.Field;
12  import java.lang.reflect.InvocationTargetException;
13  import java.lang.reflect.Method;
14  
15  import javax.xml.bind.annotation.XmlAccessType;
16  import javax.xml.bind.annotation.XmlAccessorType;
17  import javax.xml.bind.annotation.XmlTransient;
18  
19  import org.objectweb.asm.AnnotationVisitor;
20  import org.objectweb.asm.ClassReader;
21  import org.objectweb.asm.ClassVisitor;
22  import org.objectweb.asm.ClassWriter;
23  import org.objectweb.asm.FieldVisitor;
24  import org.objectweb.asm.Label;
25  import org.objectweb.asm.MethodVisitor;
26  import org.objectweb.asm.Opcodes;
27  import org.objectweb.asm.Type;
28  import org.objectweb.asm.util.CheckClassAdapter;
29  import org.objectweb.asm.util.TraceClassVisitor;
30  import org.omg.CORBA.Any;
31  
32  /**
33   * Complex TypeDef class generator.
34   * 
35   * The class generated is:
36   *
37   * <pre>
38   * {@code
39   *
40   * @XmlAccessorType(XmlAccessType.FIELD)
41   * public class MyComplexType extends ComplexType {
42   *   // @XmlTransient
43   *   // final static public MyComplexTypeHelper helperClass= MyComplexTypeHelper.class;
44   * }
45   * }
46   * </pre>
47   * 
48   * @author <a href="mailto:mpiraccini@imolinfo.it">Marco Piraccini</a>
49   */
50  @SuppressWarnings("unchecked")
51  public class ComplexTypeDef extends TypeDef {
52  	
53  	private static final String CLASS_EXTENSION = ".class";
54  	
55  	/**
56  	 * Class logger
57  	 */
58  	private static final Logger LOG = LoggerFactory
59  			.getLogger(ComplexTypeDef.class);	
60  	
61  	protected ComplexTypeDef(String className, String helperClassName, Class aliasedClass, String id) {
62  		super(className, helperClassName, aliasedClass, id);		
63  	}
64  	
65  	/**
66  	 * Removes the "Final" keyword from the Complex class (otherwise cannot be extended).
67  	 * @param classesDir
68  	 * @throws ClassGenerationException 
69  	 */
70  	private void changeFinalAliasedClass(String classesDir) throws ClassGenerationException {
71  		String filePath = aliasedClass.getName().replace('.', File.separatorChar).concat(CLASS_EXTENSION);
72  		
73  		// Absolute file path 
74  	    String absFilePath = classesDir + File.separator + filePath;	 
75  	    	    	   
76  	    ClassWriter  cw = new ClassWriter(true); // visitMaxs
77          ClassVisitor cc = new CheckClassAdapter(cw);
78          StringWriter sw = new StringWriter();
79          ClassVisitor tv = new TraceClassVisitor(cc, new PrintWriter(sw));	
80          RemoveFinalAdapter rfa = new RemoveFinalAdapter(tv);
81                         
82          ClassReader cr = Util.getAsmCLassReader(absFilePath);
83          cr.accept(rfa, true);
84          byte [] newBytecode = cw.toByteArray();
85  		
86  		LOG.debug("Class to change: " + absFilePath);
87          Util.saveAsJavaClass(absFilePath, newBytecode);		
88  	}
89  	
90  	public void createTypeDefClass(String classesDir) throws ClassGenerationException {
91  		
92  		// Removed the final keyword on the aliased class
93  		changeFinalAliasedClass(classesDir);
94  		
95  		// I have to calculate this values (i cannot load the class...doesn't exist yet)
96  		String classInternalName = this.getClassName().replace('.','/');
97  		String aliasedclassInternalName =  Type.getInternalName(aliasedClass);
98  				
99  		// helper class
100 		Class helperClass = this.getHelperClass(classesDir);  		
101 		String helperDescriptor = Type.getDescriptor(helperClass);	
102 				
103 		// Class, Object and jaxb annotations
104 		String javaLangClassDescriptor = Type.getDescriptor(Class.class);
105 		String xmlAccessorTypeDescriptor = Type.getDescriptor(XmlAccessorType.class);
106 		String xmlAccessTypeDescriptor = Type.getDescriptor(XmlAccessType.class);
107 		String xmlTransientDescriptor = Type.getDescriptor(XmlTransient.class);
108 										
109 		ClassWriter cw = new ClassWriter(true);
110 		
111 		// The class, extends the aliased class
112 		cw.visit(Opcodes.V1_5, ACC_PUBLIC + ACC_SUPER, classInternalName ,null, aliasedclassInternalName, null);
113 		
114 		// The class XmlAccessorType Annotation:	@XmlAccessorType(XmlAccessType.FIELD)
115 		AnnotationVisitor av = cw.visitAnnotation(xmlAccessorTypeDescriptor, true);		  
116         //the Annotations was changed for generate WSDL with Union Type
117         av.visitEnum("value", xmlAccessTypeDescriptor, "FIELD"); 
118 		av.visitEnd();	
119 		
120 		/* 
121 		 * @XmlTransient
122 		 * final static private Class helperClass = null; 		// cannot be inited (null) 	
123 		 */	
124 		/*
125 		FieldVisitor fvHelperClass =  cw.visitField(ACC_PRIVATE + ACC_STATIC + ACC_FINAL
126 				, "helperClass", javaLangClassDescriptor, null, null);
127 		AnnotationVisitor avHelper = fvHelperClass.visitAnnotation(xmlTransientDescriptor, true);
128 		avHelper.visitEnd();			
129 		fvHelperClass.visitEnd();
130 		*/
131 											
132 		// Class init. Inits the static "helperClass" field.	
133 		/*
134 		MethodVisitor mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
135 		mv.visitCode();
136 		Label lclinit = new Label();
137 		mv.visitLabel(lclinit);
138 		mv.visitLineNumber(10, lclinit);
139 		mv.visitLdcInsn(Type.getType(helperDescriptor));		
140 		mv.visitFieldInsn(PUTSTATIC, classInternalName, "helperClass", javaLangClassDescriptor);
141 		Label lclinit1 = new Label();
142 		mv.visitLabel(lclinit1);
143 		mv.visitLineNumber(7, lclinit1);
144 		mv.visitInsn(RETURN);
145 		mv.visitMaxs(1, 0);
146 		mv.visitEnd();
147 		*/
148 		
149 		// Default constructor	
150 		MethodVisitor mvinit = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
151 		mvinit.visitCode();
152 		Label linit = new Label();
153 		mvinit.visitLabel(linit);
154 		mvinit.visitLineNumber(7, linit);
155 		mvinit.visitVarInsn(ALOAD, 0);
156 		mvinit.visitMethodInsn(INVOKESPECIAL, aliasedclassInternalName, "<init>", "()V");
157 		mvinit.visitInsn(RETURN);	
158 		mvinit.visitMaxs(1, 1);
159 		mvinit.visitEnd();		
160 				
161 		cw.visitEnd();
162 		byte[] bytecode = cw.toByteArray();
163 		
164 		String relativeClassName = getClassRelativeFileName();
165 		
166 		if (LOG.isDebugEnabled()) {
167 			LOG.debug("Writing out TypeDef class:" + classesDir + File.separatorChar + relativeClassName);
168 		}
169 		// Writes out the class
170 		Util.saveAsJavaClass(classesDir, relativeClassName, bytecode);		
171 	}	
172 	
173 	public String toString() {
174 		return "ComplexTypeDef: " + super.toString();
175 	}	
176 
177 	public boolean isWrapped() {
178 		return false;
179 	}
180 	
181 	@Override
182 	public Object getTypeDefObject(ClassLoader classLoader, Object obj) throws ClassNotFoundException,
183 			InstantiationException, IllegalAccessException, SecurityException,
184 			NoSuchFieldException {
185 		 
186 		Class classDefinition = classLoader.loadClass(getClassName());		
187         Object typeDefObject = classDefinition.newInstance();
188         Field[] fields = obj.getClass().getFields();
189         for (int i = 0; i < fields.length; i++) {
190           fields[i].setAccessible(true);          
191           // for each class/superclass, copy all fields
192           // from this object to the clone
193           fields[i].set(typeDefObject, fields[i].get(obj));          
194         }                
195         return typeDefObject;
196 	}	
197 
198 	@Override
199 	public Object getAliasedObject(Object obj) throws SecurityException {
200 		// In this case, should be compatible (it's a subclass).
201 		return obj;
202 	}
203 
204 
205 }