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   import it.imolinfo.jbi4corba.webservice.generator.bcm.ByteCodeManipulationUtil;
8   
9   import java.io.File;
10  import java.lang.reflect.Field;
11  
12  import javax.xml.bind.annotation.XmlTransient;
13  import javax.xml.bind.annotation.XmlType;
14  import javax.xml.bind.annotation.XmlValue;
15  
16  import org.apache.commons.lang.ArrayUtils;
17  import org.apache.cxf.helpers.ServiceUtils;
18  import org.objectweb.asm.AnnotationVisitor;
19  import org.objectweb.asm.ClassWriter;
20  import org.objectweb.asm.FieldVisitor;
21  import org.objectweb.asm.Label;
22  import org.objectweb.asm.MethodVisitor;
23  import org.objectweb.asm.Opcodes;
24  import org.objectweb.asm.Type;
25  
26  /**
27   * TypeDef for Simple types (basic types + String) and array/sequences of simple types.
28   * 
29   * The class generated is:
30   *
31   * <pre>
32   * {@code
33   * @XmlType
34   * public class myint {
35   *    @XmlTransient
36   *    final static public myintHelper helperClass = myintHelper.class;
37   *    @XmlValue
38   *    public int value;
39   * }
40   * }
41   * </pre>
42   * 
43   * Or, for arrays and sequences:
44   * 
45   * <pre>
46   * {@code
47   * @XmlType
48   * public class myint {
49   *    //@XmlTransient
50   *    // final static public myintHelper helperClass = myintHelper.class;
51   *    @XmlValue
52   *    public int[] value;
53   * }
54   * }
55   * </pre>
56   * 
57   * 
58   * @author <a href="mailto:mpiraccini@imolinfo.it">Marco Piraccini</a> 
59   */
60  @SuppressWarnings("unchecked")
61  public class SimpleTypeDef extends TypeDef  {
62  	
63  	/**
64  	 * Class logger
65  	 */
66  	private static final Logger LOG = LoggerFactory
67  			.getLogger(SimpleTypeDef.class);	
68  	
69  	protected SimpleTypeDef(String className, String helperClassName, Class aliasedClass, String id) {
70  		super(className, helperClassName, aliasedClass, id);		
71  	}
72  	
73  	/**
74  	 * Creates the class for the typedef.
75  	 * 
76  	 */
77  	public void createTypeDefClass(String classesDir) throws ClassGenerationException {
78  		
79  		String namespace = ServiceUtils.makeNamespaceFromClassName(this.getClassName(), "http");
80  		
81  		// I have to calculate this values (i cannot load the class...doesn't exist yet)
82  		String classInternalName = this.getClassName().replace('.','/');
83  		String classDescriptor = "L" + classInternalName + ";";
84  		String aliasedClassDescriptor =  Type.getDescriptor(aliasedClass);
85  		String objectArrayClassDescriptor = Type.getDescriptor(java.lang.Object[].class);
86  				
87  		// helper class
88  		Class helperClass = this.getHelperClass(classesDir);  		
89  		String helperDescriptor = Type.getDescriptor(helperClass);	
90  				
91  		// Class, Object and jaxb annotations
92  		String javaLangClassDescriptor = Type.getDescriptor(Class.class);
93  		String javaLangObjectInternalName = Type.getInternalName(java.lang.Object.class);
94  		String xmlTypeDescriptor = Type.getDescriptor(XmlType.class);
95  		String xmlValueDescriptor = Type.getDescriptor(XmlValue.class);
96  		String xmlTransientDescriptor = Type.getDescriptor(XmlTransient.class);
97  								
98  		ClassWriter cw = new ClassWriter(true);
99  		
100 		// The class
101 		cw.visit(Opcodes.V1_5, ACC_PUBLIC + ACC_SUPER, classInternalName ,null, javaLangObjectInternalName, null);
102 		
103 		// The class XmlType Annotation		
104 		AnnotationVisitor av = cw.visitAnnotation(xmlTypeDescriptor, true);		
105 		av.visit("namespace", namespace);
106 		av.visitEnd();	
107 		
108 		/* 
109 		 * @XmlTransient
110 		 * final static private Class helperClass = null; 		// cannot be inited (null) 	
111 		 */			
112 		/*
113 		FieldVisitor fvHelperClass =  cw.visitField(ACC_PRIVATE + ACC_STATIC + ACC_FINAL
114 				, "helperClass", javaLangClassDescriptor, null, null);
115 		AnnotationVisitor avHelper = fvHelperClass.visitAnnotation(xmlTransientDescriptor, true);
116 		avHelper.visitEnd();			
117 		fvHelperClass.visitEnd();		
118 */												
119 		/* The field with the XmlType annotation.
120 		 * For example: 	
121 		 * @XmlValue
122 		 * public int value;
123 		 */
124 		FieldVisitor fv = null;
125 		// if (this.aliasedClass.isArray()) {
126 	    // Array (always Object[]).
127 		//	fv = cw.visitField(ACC_PUBLIC, "value", objectArrayClassDescriptor, null, null);			
128 		//} else {
129 		// Simple type
130 			fv = cw.visitField(ACC_PUBLIC, "value", aliasedClassDescriptor, null, null);
131 		// }		
132 			
133 		// This test is necesary to avoid a jaxb bug (with jaxb-impl-2.1.9).
134 		if (!aliasedClass.equals(java.lang.Object.class)) {
135 			AnnotationVisitor av2 = fv.visitAnnotation(xmlValueDescriptor, true);
136 			av2.visitEnd();		
137 			fv.visitEnd();
138 		}
139 					
140 						
141 		// Class init. Inits the static "helperClass" field.	
142 		/*
143 		MethodVisitor mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
144 		mv.visitCode();
145 		Label lclinit = new Label();
146 		mv.visitLabel(lclinit);
147 		mv.visitLineNumber(10, lclinit);
148 		mv.visitLdcInsn(Type.getType(helperDescriptor));		
149 		mv.visitFieldInsn(PUTSTATIC, classInternalName, "helperClass", javaLangClassDescriptor);
150 		Label lclinit1 = new Label();
151 		mv.visitLabel(lclinit1);
152 		mv.visitLineNumber(7, lclinit1);
153 		mv.visitInsn(RETURN);
154 		mv.visitMaxs(1, 0);
155 		mv.visitEnd();
156 		*/
157 		
158 		ByteCodeManipulationUtil bcmUtil = new ByteCodeManipulationUtil();
159 		// SETTER
160 		bcmUtil.createSetter(cw, classInternalName, "value", aliasedClassDescriptor);
161 		
162 		// GETTER
163         // bcmUtil.createGetter(cw, classInternalName, "value", aliasedClassDescriptor, false);
164 		
165 		// Default constructor		 
166 		MethodVisitor mvinit = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
167 		mvinit.visitCode();
168 		Label linit = new Label();
169 		mvinit.visitLabel(linit);
170 		mvinit.visitLineNumber(7, linit);
171 		mvinit.visitVarInsn(ALOAD, 0);
172 		mvinit.visitMethodInsn(INVOKESPECIAL, javaLangObjectInternalName, "<init>", "()V");
173 		mvinit.visitInsn(RETURN);
174 		Label linit1 = new Label();
175 		mvinit.visitLabel(linit1);
176 		mvinit.visitLocalVariable("this", classDescriptor, null, linit, linit1, 0);
177 		mvinit.visitMaxs(1, 1);
178 		mvinit.visitEnd();
179 		
180 		cw.visitEnd();
181 		byte[] bytecode = cw.toByteArray();
182 		
183 		String relativeClassName = getClassRelativeFileName();
184 		
185 		if (LOG.isDebugEnabled()) {
186 			LOG.debug("Writing out TypeDef class:" + classesDir + File.separatorChar + relativeClassName);
187 		}
188 		// Writes out the class
189 		Util.saveAsJavaClass(classesDir, relativeClassName, bytecode);		
190 	}
191 	
192 	@Override
193 	public Object getTypeDefObject(ClassLoader classLoader, Object obj) throws ClassNotFoundException, InstantiationException, IllegalAccessException, SecurityException, NoSuchFieldException {
194 		Class classDefinition = classLoader.loadClass(getClassName());
195         Object typeDefObject = classDefinition.newInstance();
196         Field value = typeDefObject.getClass().getField("value");
197         LOG.debug("Trying to set: " + obj + " of object: " + obj + " on object:" + typeDefObject);    	
198     	// This seems the only way to cast a Object[] to a String[]!!!!!
199         if (obj.getClass().isArray()) {
200         	
201         	if (LOG.isDebugEnabled()) {
202         		LOG.debug("Input: " + ArrayUtils.toString(obj));
203         	}
204          	Class aliasedClassCorrectCL = Class.forName(this.getAliasedClassName(), false, classLoader);        	        	        	        
205         	Object ob = TypeDefUtil.fillArray(obj, null, aliasedClassCorrectCL.getComponentType());
206         	if (LOG.isDebugEnabled()) {
207         		LOG.debug("Returned: " + ArrayUtils.toString(ob));
208         	}
209         	value.set(typeDefObject,ob);
210         	
211         	/*
212         	Vector v = new Vector();
213         	Object[] myarr = (Object[]) obj;  
214         	for (int i = 0; i < myarr.length; i++) {      
215         		v.add(myarr[i]);        		        	
216         	}
217         	Object[] ob = (Object[])Array.newInstance(aliasedClass.getComponentType(), 0);
218         	value.set(typeDefObject,v.toArray(ob));
219         	*/        	            		
220         } else {        	
221         	value.set(typeDefObject, obj);
222         }
223         return typeDefObject;
224 	}
225 	
226 	@Override
227 	public Object getAliasedObject(Object obj) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
228 		Field value = obj.getClass().getField("value");
229 		Object objValue = value.get(obj);
230 		return objValue;	
231 	}
232 	
233 	@Override	
234 	public String toString() {
235 		return "SimpleTypeDef: " + super.toString();
236 	}
237 	
238 	
239 }