1 /*******************************************************************************
2 * Copyright (c) 2007, 2011 Association for Decentralized Information Management in
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.databoard.binding.reflection;
14 import java.lang.reflect.Field;
15 import java.lang.reflect.Method;
16 import java.lang.reflect.Modifier;
17 import java.util.HashMap;
20 import org.objectweb.asm.AnnotationVisitor;
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.simantics.databoard.binding.error.BindingConstructionException;
30 public class AsmBindingClassLoader extends ClassLoader implements Opcodes {
32 Map<String, Class<?>> map = new HashMap<String, Class<?>>();
34 public AsmBindingClassLoader() {
35 super(Thread.currentThread().getContextClassLoader());
38 public AsmBindingClassLoader(ClassLoader parent) {
42 public String toBindingClassName( String targetClassName )
44 if ( targetClassName.startsWith("java" ) ) {
45 return "x"+targetClassName+".Binding";
47 return targetClassName+".Binding";
50 public String toTargetClassName( String bindingClassName )
52 if (!bindingClassName.endsWith(".Binding")) return null;
53 if (bindingClassName.substring(1,5).equals("java")) {
54 return bindingClassName.substring(1, bindingClassName.length()-8);
56 return bindingClassName.substring(0, bindingClassName.length()-8);
61 protected synchronized Class<?> findClass(String bindingClassName)
62 throws ClassNotFoundException
64 Class<?> c = map.get(bindingClassName);
65 if ( c!= null) return c;
68 String targetClassName = toTargetClassName(bindingClassName);
69 if ( targetClassName == null ) {
71 return super.findClass(bindingClassName);
72 // } catch( ClassNotFoundException e ) {
73 // e.printStackTrace();
78 ClassLoader cl = getParent();
80 cl = Thread.currentThread().getContextClassLoader();
82 Class<?> targetClass = cl.loadClass( targetClassName );
83 ClassInfo ci = ClassInfo.getInfo( targetClass );
84 byte[] data = createBindingClass( ci, bindingClassName );
85 Class<?> bindingClass = defineClass( bindingClassName, data, 0, data.length );
86 map.put(bindingClassName, bindingClass);
88 } catch (BindingConstructionException e) {
89 throw new ClassNotFoundException( e.getMessage(), e.getCause() );
93 public synchronized Class<?> getBindingClass(Class<?> targetClass)
94 throws ClassNotFoundException
96 String targetClassName = targetClass.getName();
97 String bindingClassName = toBindingClassName(targetClassName);
98 Class<?> c = map.get(bindingClassName);
99 if ( c!= null) return c;
102 ClassInfo ci = ClassInfo.getInfo( targetClass );
103 byte[] data = createBindingClass( ci, bindingClassName );
104 Class<?> bindingClass = defineClass( bindingClassName, data, 0, data.length );
105 map.put(bindingClassName, bindingClass);
107 } catch (BindingConstructionException e) {
108 throw new ClassNotFoundException( e.getMessage(), e.getCause() );
113 public byte[] createBindingClass(ClassInfo ci, String bindingClassName)
115 //System.out.println("BindingFactory: "+bindingClassName+" (for "+ci.clazz.getClassLoader()+")");
116 int count = ci.fields.length;
117 ClassWriter cw = new ClassWriter( ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS );
118 ClassVisitor cv = cw;//new CheckClassAdapter(cw);
122 AnnotationVisitor av0;
124 String className = ci.clazz.getName().replaceAll("\\.", "/");
125 bindingClassName = bindingClassName.replaceAll("\\.", "/");
126 Object[] classNameX = new Object[] {className};
127 String signature = "L"+bindingClassName+";";
130 String superClass = "org/simantics/databoard/binding/reflection/ClassBinding";
131 cv.visit(V1_6, ACC_PUBLIC + ACC_SUPER, bindingClassName, null, superClass, null);
135 mv = cv.visitMethod(ACC_PUBLIC, "<init>", "(Lorg/simantics/databoard/type/RecordType;)V", null, new String[] { "org/simantics/databoard/binding/error/BindingConstructionException" });
138 Label l0 = new Label();
140 mv.visitVarInsn(ALOAD, 0);
141 mv.visitLdcInsn(Type.getType("L"+className+";"));
142 mv.visitMethodInsn(INVOKESPECIAL, superClass, "<init>", "(Ljava/lang/Class;)V");
144 Label l1 = new Label();
146 mv.visitVarInsn(ALOAD, 0);
147 mv.visitVarInsn(ALOAD, 1);
148 mv.visitFieldInsn(PUTFIELD, bindingClassName, "type", "Lorg/simantics/databoard/type/Datatype;");
150 Label l2 = new Label();
152 mv.visitInsn(RETURN);
154 Label l3 = new Label();
156 mv.visitLocalVariable("this", signature, null, l0, l3, 0);
157 mv.visitLocalVariable("type", "Lorg/simantics/databoard/type/RecordType;", null, l0, l3, 1);
164 mv = cv.visitMethod(ACC_PUBLIC, "getComponent", "(Ljava/lang/Object;I)Ljava/lang/Object;", null, new String[] { "org/simantics/databoard/binding/error/BindingException" });
166 Label l0 = new Label();
168 mv.visitVarInsn(ALOAD, 1);
169 mv.visitTypeInsn(CHECKCAST, className);
170 mv.visitVarInsn(ASTORE, 3);
171 Label l1 = new Label();
174 Label caseLabels[] = createFieldLabels( ci );
175 Label elseLabel = new Label();
179 mv.visitVarInsn(ILOAD, 2);
180 mv.visitTableSwitchInsn(0, count-1, elseLabel, caseLabels);
182 // case i: x.field = value[i]
183 for (int i=0; i<count; i++) {
184 Label label = caseLabels[i];
185 Field field = ci.fields[i];
186 String fieldName = field.getName();
187 Class<?> fieldClass = ci.fields[i].getType();
188 String typeDescriptor = toTypeDescriptor( fieldClass );
190 Method getter = ci.getters[i];
191 boolean useGetter = ((field.getModifiers() & Modifier.PUBLIC) == 0) && getter!=null;
193 mv.visitLabel( label );
195 mv.visitFrame(Opcodes.F_APPEND,1, classNameX, 0, null);
197 mv.visitFrame(Opcodes.F_SAME,0, null, 0, null);
200 // Read instance argument
201 mv.visitVarInsn(ALOAD, 3);
205 mv.visitMethodInsn(INVOKEVIRTUAL, className, getter.getName(), "()"+typeDescriptor);
208 mv.visitFieldInsn(GETFIELD, className, fieldName, typeDescriptor);
214 mv.visitInsn(ARETURN);
219 mv.visitLabel(elseLabel);
221 mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
223 mv.visitTypeInsn(NEW, "org/simantics/databoard/binding/error/BindingException");
225 mv.visitLdcInsn("Illegal field index");
226 mv.visitMethodInsn(INVOKESPECIAL, "org/simantics/databoard/binding/error/BindingException", "<init>", "(Ljava/lang/String;)V");
227 mv.visitInsn(ATHROW);
230 Label l19 = new Label();
232 mv.visitLocalVariable("this", "L"+className+";", null, l0, l19, 0);
233 mv.visitLocalVariable("obj", "Ljava/lang/Object;", null, l0, l19, 1);
234 mv.visitLocalVariable("index", "I", null, l0, l19, 2);
235 //mv.visitLocalVariable("x", "Lorg/simantics/databoard/binding/reflection/MyClass;", null, l1, l19, 3);
242 mv = cv.visitMethod(ACC_PUBLIC + ACC_VARARGS, "create", "([Ljava/lang/Object;)Ljava/lang/Object;", null, new String[] { "org/simantics/databoard/binding/error/BindingException" });
243 if ( ci.beanConstructor != null ) {
245 Label l0 = new Label();
247 mv.visitTypeInsn(NEW, className);
249 mv.visitVarInsn(ALOAD, 0);
250 mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", "(Lorg/simantics/databoard/binding/Binding;)V");
251 mv.visitVarInsn(ASTORE, 2);
252 Label l1 = new Label();
254 mv.visitVarInsn(ALOAD, 0);
255 mv.visitVarInsn(ALOAD, 2);
256 mv.visitVarInsn(ALOAD, 1);
257 mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "setComponents", "(Ljava/lang/Object;[Ljava/lang/Object;)V");
258 Label l2 = new Label();
260 mv.visitVarInsn(ALOAD, 2);
261 mv.visitInsn(ARETURN);
262 Label l3 = new Label();
264 mv.visitLocalVariable("this", "L"+bindingClassName+";", null, l0, l3, 0);
265 mv.visitLocalVariable("values", "[Ljava/lang/Object;", null, l0, l3, 1);
266 //mv.visitLocalVariable("x", "L"+className+";", null, l1, l3, 2);
269 } else if ( ci.argsConstructor != null ) {
271 Label l0 = new Label();
273 mv.visitTypeInsn(NEW, className);
276 String constArgsDescriptor = "(";
277 Class<?>[] args = ci.argsConstructor.getParameterTypes();
278 for (int i=0; i<count; i++) {
279 Label label = new Label();
280 Class<?> field = args[i];
281 String fieldName = field.getName();
282 Method getter = ci.getters[i];
283 Class<?> fieldClass = ci.fields[i].getType();
284 Class<?> boxClass = getBoxClass(fieldClass);
285 String typeDescriptor = toTypeDescriptor( fieldClass );
286 String boxTypeDescriptor = toTypeDescriptor( boxClass );
287 constArgsDescriptor += typeDescriptor;
289 mv.visitLabel(label);
290 mv.visitVarInsn(ALOAD, 1);
292 mv.visitInsn(ICONST_0 + i);
294 mv.visitIntInsn(BIPUSH, i);
297 mv.visitInsn(AALOAD);
298 mv.visitTypeInsn(CHECKCAST, toClassCanonicalName(boxClass));
299 unbox(mv, fieldClass);
302 Label l17 = new Label();
304 constArgsDescriptor += ")V";
305 mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", constArgsDescriptor);
306 mv.visitInsn(ARETURN);
307 Label l18 = new Label();
309 mv.visitLocalVariable("this", "L"+bindingClassName+";", null, l0, l18, 0);
310 mv.visitLocalVariable("values", "[Ljava/lang/Object;", null, l0, l18, 1);
316 Label l0 = new Label();
318 mv.visitTypeInsn(NEW, className);
320 mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", "()V");
321 mv.visitVarInsn(ASTORE, 2);
322 Label l1 = new Label();
324 mv.visitVarInsn(ALOAD, 0);
325 mv.visitVarInsn(ALOAD, 2);
326 mv.visitVarInsn(ALOAD, 1);
327 mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "setComponents", "(Ljava/lang/Object;[Ljava/lang/Object;)V");
328 Label l2 = new Label();
330 mv.visitVarInsn(ALOAD, 2);
331 mv.visitInsn(ARETURN);
332 Label l3 = new Label();
334 mv.visitLocalVariable("this", "L"+bindingClassName+";", null, l0, l3, 0);
335 mv.visitLocalVariable("values", "[Ljava/lang/Object;", null, l0, l3, 1);
336 //mv.visitLocalVariable("x", "L"+className+";", null, l1, l3, 2);
343 mv = cv.visitMethod(ACC_PUBLIC, "createPartial", "()Ljava/lang/Object;", null, new String[] { "org/simantics/databoard/binding/error/BindingException" });
344 if (ci.beanConstructor!=null)
347 Label l0 = new Label();
349 mv.visitTypeInsn(NEW, className);
351 mv.visitVarInsn(ALOAD, 0);
352 mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", "(Lorg/simantics/databoard/binding/Binding;)V");
353 mv.visitInsn(ARETURN);
354 Label l1 = new Label();
356 mv.visitLocalVariable("this", "L"+bindingClassName+";", null, l0, l1, 0);
359 } else if (ci.noArgsConstructor != null)
361 // return new MyClass();
363 Label l0 = new Label();
365 mv.visitTypeInsn(NEW, className);
367 mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", "()V");
368 mv.visitInsn(ARETURN);
369 Label l1 = new Label();
371 mv.visitLocalVariable("this", "L"+bindingClassName+";", null, l0, l1, 0);
376 Label l0 = new Label();
378 mv.visitIntInsn(BIPUSH, count);
379 mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
380 mv.visitVarInsn(ASTORE, 1);
381 Label l1 = new Label();
383 mv.visitInsn(ICONST_0);
384 mv.visitVarInsn(ISTORE, 2);
385 Label l2 = new Label();
387 Label l3 = new Label();
388 mv.visitJumpInsn(GOTO, l3);
389 Label l4 = new Label();
391 mv.visitFrame(Opcodes.F_APPEND,2, new Object[] {"[Ljava/lang/Object;", Opcodes.INTEGER}, 0, null);
392 mv.visitVarInsn(ALOAD, 0);
393 mv.visitFieldInsn(GETFIELD, bindingClassName, "componentBindings", "[Lorg/simantics/databoard/binding/Binding;");
394 mv.visitVarInsn(ILOAD, 2);
395 mv.visitInsn(AALOAD);
396 mv.visitVarInsn(ASTORE, 3);
397 Label l5 = new Label();
399 mv.visitVarInsn(ALOAD, 1);
400 mv.visitVarInsn(ILOAD, 2);
401 mv.visitVarInsn(ALOAD, 3);
402 mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/Binding", "createDefault", "()Ljava/lang/Object;");
403 mv.visitInsn(AASTORE);
404 Label l6 = new Label();
406 mv.visitIincInsn(2, 1);
408 mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
409 mv.visitVarInsn(ILOAD, 2);
410 mv.visitVarInsn(ALOAD, 1);
411 mv.visitInsn(ARRAYLENGTH);
412 mv.visitJumpInsn(IF_ICMPLT, l4);
413 Label l7 = new Label();
415 mv.visitLineNumber(109, l7);
416 mv.visitVarInsn(ALOAD, 0);
417 mv.visitVarInsn(ALOAD, 1);
418 mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "create", "([Ljava/lang/Object;)Ljava/lang/Object;");
419 mv.visitInsn(ARETURN);
420 Label l8 = new Label();
422 mv.visitLocalVariable("this", "L"+bindingClassName+";", null, l0, l8, 0);
423 mv.visitLocalVariable("values", "[Ljava/lang/Object;", null, l1, l8, 1);
424 mv.visitLocalVariable("i", "I", null, l2, l7, 2);
425 mv.visitLocalVariable("fb", "Lorg/simantics/databoard/binding/Binding;", null, l5, l6, 3);
432 mv = cv.visitMethod(ACC_PUBLIC, "setComponent", "(Ljava/lang/Object;ILjava/lang/Object;)V", null, new String[] { "org/simantics/databoard/binding/error/BindingException" });
434 Label l0 = new Label();
436 mv.visitVarInsn(ALOAD, 1);
437 mv.visitTypeInsn(CHECKCAST, className);
438 mv.visitVarInsn(ASTORE, 4);
439 Label endLabel = new Label();
440 Label l1 = new Label();
443 Label elseLabel = new Label();
444 Label labels[] = new Label[ count ];
445 for (int i=0; i<count; i++) labels[i] = new Label();
448 mv.visitVarInsn(ILOAD, 2);
449 mv.visitTableSwitchInsn(0, count-1, elseLabel, labels);
451 for (int i=0; i<count; i++) {
452 Label label = labels[ i ];
453 mv.visitLabel(label);
454 Field field = ci.fields[i];
455 String fieldName = field.getName();
456 Class<?> fieldClass = ci.fields[i].getType();
457 Class<?> boxClass = getBoxClass(fieldClass);
458 String typeDescriptor = toTypeDescriptor( fieldClass );
459 String boxTypeDescriptor = toTypeDescriptor( boxClass );
461 Method setter = ci.setters[i];
462 Class<?> setterClass = setter!=null?setter.getParameterTypes()[0]:null;
463 boolean useSetter = ((field.getModifiers() & Modifier.PUBLIC) == 0) && setter!=null;
466 mv.visitFrame(Opcodes.F_APPEND,1, classNameX, 0, null);
468 mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
470 mv.visitVarInsn(ALOAD, 4);
471 mv.visitVarInsn(ALOAD, 3);
472 mv.visitTypeInsn(CHECKCAST, toClassCanonicalName(boxClass));
475 unbox(mv, setterClass);
476 mv.visitMethodInsn(INVOKEVIRTUAL, className, setter.getName(), "("+typeDescriptor+")V");
478 unbox(mv, fieldClass);
479 mv.visitFieldInsn(PUTFIELD, className, field.getName(), typeDescriptor);
481 mv.visitInsn(RETURN);
485 mv.visitLabel(elseLabel);
486 mv.visitLineNumber(178, elseLabel);
488 mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
490 mv.visitTypeInsn(NEW, "org/simantics/databoard/binding/error/BindingException");
492 mv.visitLdcInsn("Illegal field index");
493 mv.visitMethodInsn(INVOKESPECIAL, "org/simantics/databoard/binding/error/BindingException", "<init>", "(Ljava/lang/String;)V");
494 mv.visitInsn(ATHROW);
496 mv.visitLabel(endLabel);
497 mv.visitLocalVariable("this", "L"+bindingClassName+";", null, l0, endLabel, 0);
498 mv.visitLocalVariable("obj", "Ljava/lang/Object;", null, l0, endLabel, 1);
499 mv.visitLocalVariable("index", "I", null, l0, endLabel, 2);
500 mv.visitLocalVariable("value", "Ljava/lang/Object;", null, l0, endLabel, 3);
501 //mv.visitLocalVariable("x", "L"+className+";", null, l1, endLabel, 4);
508 mv = cv.visitMethod(ACC_PUBLIC, "isImmutable", "()Z", null, null);
510 Label l0 = new Label();
512 mv.visitInsn(ICONST_0);
513 mv.visitInsn(IRETURN);
514 Label l1 = new Label();
516 mv.visitLocalVariable("this", "L"+className+";", null, l0, l1, 0);
523 mv = cv.visitMethod(ACC_PUBLIC, "isInstance", "(Ljava/lang/Object;)Z", null, null);
525 Label l0 = new Label();
527 mv.visitVarInsn(ALOAD, 1);
528 mv.visitTypeInsn(INSTANCEOF, className);
529 mv.visitInsn(IRETURN);
530 Label l1 = new Label();
532 mv.visitLocalVariable("this", "L"+className+";", null, l0, l1, 0);
533 mv.visitLocalVariable("obj", "Ljava/lang/Object;", null, l0, l1, 1);
540 mv = cv.visitMethod(ACC_PUBLIC + ACC_VARARGS, "setComponents", "(Ljava/lang/Object;[Ljava/lang/Object;)V", null, new String[] { "org/simantics/databoard/binding/error/BindingException" });
542 Label l0 = new Label();
544 mv.visitVarInsn(ALOAD, 1);
545 mv.visitTypeInsn(CHECKCAST, className);
546 mv.visitVarInsn(ASTORE, 3);
547 Label firstLabel = l0;
549 for (int i=0; i<count; i++) {
550 Label label = new Label();
551 if (firstLabel==l0) firstLabel = label;
552 Field field = ci.fields[i];
553 String fieldName = field.getName();
554 Class<?> fieldClass = ci.fields[i].getType();
555 Class<?> boxClass = getBoxClass(fieldClass);
556 String typeDescriptor = toTypeDescriptor( fieldClass );
557 String boxTypeDescriptor = toTypeDescriptor( boxClass );
559 Method setter = ci.setters[i];
560 Class<?> setterClass = setter!=null?setter.getParameterTypes()[0]:null;
561 boolean useSetter = ((field.getModifiers() & Modifier.PUBLIC) == 0) && setter!=null;
563 mv.visitLabel(label);
564 mv.visitVarInsn(ALOAD, 3);
565 mv.visitVarInsn(ALOAD, 2);
567 mv.visitInsn(ICONST_0 + i);
569 mv.visitIntInsn(BIPUSH, i);
571 mv.visitInsn(AALOAD);
572 mv.visitTypeInsn(CHECKCAST, toClassCanonicalName(boxClass));
575 unbox(mv, setterClass);
576 mv.visitMethodInsn(INVOKEVIRTUAL, className, setter.getName(), "("+typeDescriptor+")V");
578 unbox(mv, fieldClass);
579 mv.visitFieldInsn(PUTFIELD, className, field.getName(), typeDescriptor);
583 Label l17 = new Label();
585 mv.visitInsn(RETURN);
586 Label endLabel = new Label();
587 mv.visitLabel(endLabel);
588 mv.visitLocalVariable("this", "L"+className+";", null, l0, endLabel, 0);
589 mv.visitLocalVariable("obj", "Ljava/lang/Object;", null, l0, endLabel, 1);
590 mv.visitLocalVariable("value", "[Ljava/lang/Object;", null, l0, endLabel, 2);
591 //mv.visitLocalVariable("x", "Lorg/simantics/databoard/binding/reflection/MyClass;", null, firstLabel, endLabel, 3);
596 // Add primitive setters
598 addGetSetPrimitive(ci, cv, "Boolean", "Z", bindingClassName);
599 addGetSetPrimitive(ci, cv, "Byte", "B", bindingClassName);
600 addGetSetPrimitive(ci, cv, "Int", "I", bindingClassName);
601 addGetSetPrimitive(ci, cv, "Long", "J", bindingClassName);
602 addGetSetPrimitive(ci, cv, "Float", "F", bindingClassName);
603 addGetSetPrimitive(ci, cv, "Double", "D", bindingClassName);
607 return cw.toByteArray();
610 private void addGetSetPrimitive(ClassInfo ci, ClassVisitor cv, String setterName, String signature, String bindingClassName)
612 String className = ci.clazz.getName().replaceAll("\\.", "/");
614 Label firstLabel = new Label();
615 Label secondLabel = new Label();
616 Label errorLabel = new Label();
617 Label exitLabel = new Label();
618 Label lastLabel = new Label();
620 boolean oneByte = !signature.equals("J") && !signature.equals("D");
623 for (Field f : ci.fields) {
624 if ( toTypeDescriptor(getPrimitiveClass(f.getType())).equals( signature ) ) c++;
627 int[] indices = new int[ c ];
628 Label[] caseLabel = new Label[ c ];
631 for (int i=0; i<ci.fields.length; i++)
633 Class<?> fieldClass = ci.fields[i].getType();
634 fieldClass = getPrimitiveClass(fieldClass);
635 String s = toTypeDescriptor(fieldClass);
636 if ( !s.equals( signature ) ) continue;
639 caseLabel[c] = new Label();
646 MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "set"+setterName, "(Ljava/lang/Object;I"+signature+")V", null, new String[] { "org/simantics/databoard/binding/error/BindingException" });
648 mv.visitLabel(firstLabel);
649 mv.visitVarInsn(ALOAD, 1);
650 mv.visitTypeInsn(CHECKCAST, className);
651 mv.visitVarInsn(ASTORE, oneByte?4:5);
653 mv.visitLabel(secondLabel);
654 mv.visitVarInsn(ILOAD, 2);
657 mv.visitLookupSwitchInsn(errorLabel, indices, caseLabel);
661 for (int i=0; i<c; i++) {
662 int index = indices[i];
663 Method setter = ci.setters[index];
664 Field field = ci.fields[index];
665 Class<?> fieldClass = field.getType();
666 Class<?> setterClass = setter!=null?setter.getParameterTypes()[0]:null;
667 boolean useSetter = ((field.getModifiers() & Modifier.PUBLIC) == 0) && setter!=null;
668 String typeDescriptor = toTypeDescriptor( useSetter ? setterClass : fieldClass );
670 mv.visitLabel(caseLabel[i]);
672 mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {className}, 0, null);
674 mv.visitFrame(Opcodes.F_SAME, 0, new Object[] {className}, 0, null);
676 if ( signature.equals("F") ) {
677 mv.visitVarInsn(ALOAD, 4);
678 mv.visitVarInsn(FLOAD, 3);
679 } else if ( signature.equals("D") ) {
680 mv.visitVarInsn(ALOAD, 5);
681 mv.visitVarInsn(DLOAD, 3);
682 } else if ( signature.equals("J") ) {
683 mv.visitVarInsn(ALOAD, 5);
684 mv.visitVarInsn(LLOAD, 3);
686 mv.visitVarInsn(ALOAD, 4);
687 mv.visitVarInsn(ILOAD, 3);
691 boxTo(mv, setterClass);
692 mv.visitMethodInsn(INVOKEVIRTUAL, className, setter.getName(), "("+typeDescriptor+")V");
694 boxTo(mv, fieldClass);
695 mv.visitFieldInsn(PUTFIELD, className, field.getName(), typeDescriptor);
697 mv.visitJumpInsn(GOTO, exitLabel);
705 mv.visitLabel(errorLabel);
706 mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
707 mv.visitTypeInsn(NEW, "org/simantics/databoard/binding/error/BindingException");
709 mv.visitLdcInsn("Field is not "+setterName);
710 mv.visitMethodInsn(INVOKESPECIAL, "org/simantics/databoard/binding/error/BindingException", "<init>", "(Ljava/lang/String;)V");
711 mv.visitInsn(ATHROW);
714 // default: setComponent
715 mv.visitLabel(errorLabel);
716 mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
717 mv.visitVarInsn(ALOAD, 0);
718 mv.visitVarInsn(ALOAD, 1);
719 mv.visitVarInsn(ILOAD, 2);
720 mv.visitVarInsn(ALOAD, 0);
721 mv.visitFieldInsn(GETFIELD, bindingClassName, "componentBindings", "[Lorg/simantics/databoard/binding/Binding;");
722 mv.visitVarInsn(ILOAD, 2);
723 mv.visitInsn(AALOAD);
724 if ( signature.equals("F") ) {
725 mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/FloatBinding");
726 mv.visitVarInsn(FLOAD, 3);
727 mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/FloatBinding", "create", "(F)Ljava/lang/Object;");
728 } else if ( signature.equals("D") ) {
729 mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/DoubleBinding");
730 mv.visitVarInsn(DLOAD, 3);
731 mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/DoubleBinding", "create", "(D)Ljava/lang/Object;");
732 } else if ( signature.equals("J") ) {
733 mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/LongBinding");
734 mv.visitVarInsn(LLOAD, 3);
735 mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/LongBinding", "create", "(J)Ljava/lang/Object;");
736 } else if ( signature.equals("Z") ){
737 mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/BooleanBinding");
738 mv.visitVarInsn(ILOAD, 3);
739 mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/BooleanBinding", "create", "(Z)Ljava/lang/Object;");
740 } else if ( signature.equals("I") ){
741 mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/IntBinding");
742 mv.visitVarInsn(ILOAD, 3);
743 mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/IntBinding", "create", "(I)Ljava/lang/Object;");
744 } else if ( signature.equals("B") ){
745 mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/ByteBinding");
746 mv.visitVarInsn(ILOAD, 3);
747 mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/ByteBinding", "create", "(B)Ljava/lang/Object;");
749 mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "setComponent", "(Ljava/lang/Object;ILjava/lang/Object;)V");
752 mv.visitLabel(exitLabel);
753 mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
754 mv.visitInsn(RETURN);
756 // Something at the end
757 mv.visitLabel(lastLabel);
758 // mv.visitLocalVariable("this", "L"+bindingClassName+";", null, firstLabel, lastLabel, 0);
759 // mv.visitLocalVariable("r", "Ljava/lang/Object;", null, firstLabel, lastLabel, 1);
760 // mv.visitLocalVariable("index", "I", null, firstLabel, lastLabel, 2);
761 // mv.visitLocalVariable("z", signature, null, firstLabel, lastLabel, 3);
762 // mv.visitLocalVariable("x", "L"+className+";", null, secondLabel, lastLabel, 4);
763 mv.visitMaxs(oneByte?5:6, oneByte?5:6);
770 firstLabel = new Label();
771 secondLabel = new Label();
772 errorLabel = new Label();
773 exitLabel = new Label();
774 lastLabel = new Label();
775 for (int i=0; i<c; i++) caseLabel[i] = new Label();
776 mv = cv.visitMethod(ACC_PUBLIC, "get"+setterName, "(Ljava/lang/Object;I)"+signature, null, new String[] { "org/simantics/databoard/binding/error/BindingException" });
778 mv.visitLabel(firstLabel);
779 mv.visitVarInsn(ALOAD, 1);
780 mv.visitTypeInsn(CHECKCAST, className);
781 mv.visitVarInsn(ASTORE, 3);
783 mv.visitLabel(secondLabel);
784 mv.visitVarInsn(ILOAD, 2);
788 mv.visitLookupSwitchInsn(errorLabel, indices, caseLabel);
791 for (int i=0; i<c; i++) {
792 int index = indices[i];
793 Method getter = ci.getters[index];
794 Field field = ci.fields[index];
795 Class<?> fieldClass = field.getType();
796 Class<?> getterClass = getter!=null?getter.getReturnType():null;
797 boolean useGetter = ((field.getModifiers() & Modifier.PUBLIC) == 0) && getter!=null;
798 String typeDescriptor = toTypeDescriptor( useGetter ? getterClass : fieldClass );
800 mv.visitLabel(caseLabel[i]);
802 mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {className}, 0, null);
804 mv.visitFrame(Opcodes.F_SAME, 0, new Object[] {className}, 0, null);
807 mv.visitVarInsn(ALOAD, 3);
810 mv.visitMethodInsn(INVOKEVIRTUAL, className, getter.getName(), "()"+typeDescriptor);
811 unboxFrom(mv, getterClass);
813 mv.visitFieldInsn(GETFIELD, className, field.getName(), typeDescriptor);
814 unboxFrom(mv, fieldClass);
817 if ( signature.equals("F") ) {
818 mv.visitInsn(FRETURN);
819 } else if ( signature.equals("D") ) {
820 mv.visitInsn(DRETURN);
821 } else if ( signature.equals("J") ) {
822 mv.visitInsn(LRETURN);
824 mv.visitInsn(IRETURN);
833 mv.visitLabel(errorLabel);
834 mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
835 mv.visitTypeInsn(NEW, "org/simantics/databoard/binding/error/BindingException");
837 mv.visitLdcInsn("Field is not "+setterName);
838 mv.visitMethodInsn(INVOKESPECIAL, "org/simantics/databoard/binding/error/BindingException", "<init>", "(Ljava/lang/String;)V");
839 mv.visitInsn(ATHROW);
843 mv.visitLabel(errorLabel);
844 mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
845 mv.visitVarInsn(ALOAD, 0);
846 mv.visitFieldInsn(GETFIELD, bindingClassName, "componentBindings", "[Lorg/simantics/databoard/binding/Binding;");
847 mv.visitVarInsn(ILOAD, 2);
848 mv.visitInsn(AALOAD);
849 if ( signature.equals("Z") ) {
850 mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/BooleanBinding");
851 mv.visitVarInsn(ALOAD, 0);
852 mv.visitVarInsn(ALOAD, 1);
853 mv.visitVarInsn(ILOAD, 2);
854 mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "getComponent", "(Ljava/lang/Object;I)Ljava/lang/Object;");
855 mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/BooleanBinding", "getValue_", "(Ljava/lang/Object;)Z");
856 mv.visitInsn(IRETURN);
857 } else if ( signature.equals("B") ) {
858 mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/ByteBinding");
859 mv.visitVarInsn(ALOAD, 0);
860 mv.visitVarInsn(ALOAD, 1);
861 mv.visitVarInsn(ILOAD, 2);
862 mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "getComponent", "(Ljava/lang/Object;I)Ljava/lang/Object;");
863 mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/ByteBinding", "getValue_", "(Ljava/lang/Object;)B");
864 mv.visitInsn(IRETURN);
865 } else if ( signature.equals("I") ) {
866 mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/IntBinding");
867 mv.visitVarInsn(ALOAD, 0);
868 mv.visitVarInsn(ALOAD, 1);
869 mv.visitVarInsn(ILOAD, 2);
870 mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "getComponent", "(Ljava/lang/Object;I)Ljava/lang/Object;");
871 mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/IntBinding", "getValue_", "(Ljava/lang/Object;)I");
872 mv.visitInsn(IRETURN);
873 } else if ( signature.equals("J") ) {
874 mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/LongBinding");
875 mv.visitVarInsn(ALOAD, 0);
876 mv.visitVarInsn(ALOAD, 1);
877 mv.visitVarInsn(ILOAD, 2);
878 mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "getComponent", "(Ljava/lang/Object;I)Ljava/lang/Object;");
879 mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/LongBinding", "getValue_", "(Ljava/lang/Object;)J");
880 mv.visitInsn(LRETURN);
881 } else if ( signature.equals("F") ) {
882 mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/FloatBinding");
883 mv.visitVarInsn(ALOAD, 0);
884 mv.visitVarInsn(ALOAD, 1);
885 mv.visitVarInsn(ILOAD, 2);
886 mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "getComponent", "(Ljava/lang/Object;I)Ljava/lang/Object;");
887 mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/FloatBinding", "getValue_", "(Ljava/lang/Object;)F");
888 mv.visitInsn(FRETURN);
889 } else if ( signature.equals("D") ) {
890 mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/DoubleBinding");
891 mv.visitVarInsn(ALOAD, 0);
892 mv.visitVarInsn(ALOAD, 1);
893 mv.visitVarInsn(ILOAD, 2);
894 mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "getComponent", "(Ljava/lang/Object;I)Ljava/lang/Object;");
895 mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/DoubleBinding", "getValue_", "(Ljava/lang/Object;)D");
896 mv.visitInsn(DRETURN);
899 // Something at the end
900 mv.visitLabel(lastLabel);
901 // mv.visitLocalVariable("this", "Lorg/simantics/databoard/binding/reflection/MyBinding;", null, firstLabel, lastLabel, 0);
902 // mv.visitLocalVariable("r", "Ljava/lang/Object;", null, firstLabel, lastLabel, 1);
903 // mv.visitLocalVariable("index", "I", null, firstLabel, lastLabel, 2);
904 // mv.visitLocalVariable("x", "Lorg/simantics/databoard/binding/reflection/MyClass;", null, secondLabel, lastLabel, 3);
911 public static Label[] createFieldLabels(ClassInfo ci)
913 Label caseLabels[] = new Label[ ci.fields.length ];
914 for (int i=0; i<ci.fields.length; i++) caseLabels[i] = new Label();
918 public static String toTypeDescriptor(Class<?> clazz) {
919 if (clazz==void.class) return "V";
920 if (clazz==boolean.class) return "Z";
921 if (clazz==char.class) return "C";
922 if (clazz==byte.class) return "B";
923 if (clazz==short.class) return "S";
924 if (clazz==int.class) return "I";
925 if (clazz==float.class) return "F";
926 if (clazz==long.class) return "J";
927 if (clazz==double.class) return "D";
928 if (clazz.isArray()) return clazz.getName().replaceAll("\\.", "/");
929 return "L"+clazz.getName().replaceAll("\\.", "/")+";";
933 * Get respective boxed class
937 public static Class<?> getBoxClass(Class<?> clazz) {
938 if (clazz==void.class) return null;
939 if (clazz==boolean.class) return Boolean.class;
940 if (clazz==char.class) return Character.class;
941 if (clazz==byte.class) return Byte.class;
942 if (clazz==short.class) return Short.class;
943 if (clazz==int.class) return Integer.class;
944 if (clazz==float.class) return Float.class;
945 if (clazz==long.class) return Long.class;
946 if (clazz==double.class) return Double.class;
951 * Get respective primitive class
953 * @return primitive-class
955 public static Class<?> getPrimitiveClass(Class<?> clazz) {
956 if (clazz==Boolean.class) return boolean.class;
957 if (clazz==Character.class) return char.class;
958 if (clazz==Byte.class) return byte.class;
959 if (clazz==Short.class) return short.class;
960 if (clazz==Integer.class) return int.class;
961 if (clazz==Float.class) return float.class;
962 if (clazz==Long.class) return long.class;
963 if (clazz==Double.class) return double.class;
967 public static boolean isPrimitive(Class<?> clazz) {
968 return clazz==boolean.class || clazz==char.class || clazz==byte.class ||
969 clazz==short.class || clazz==int.class || clazz==float.class ||
970 clazz==long.class || clazz==double.class;
973 public static void unbox(MethodVisitor mv, Class<?> clazz) {
974 if (clazz==boolean.class) {
975 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
976 } else if (clazz==char.class) {
977 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C"); // C?
978 } else if (clazz==byte.class) {
979 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B");
980 } else if (clazz==short.class) {
981 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
982 } else if (clazz==int.class) {
983 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
984 } else if (clazz==float.class) {
985 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
986 } else if (clazz==long.class) {
987 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
988 } else if (clazz==double.class) {
989 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
993 public static void box(MethodVisitor mv, Class<?> clazz) {
994 if (clazz==boolean.class) {
995 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
996 } else if (clazz==char.class) {
997 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
998 } else if (clazz==byte.class) {
999 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
1000 } else if (clazz==short.class) {
1001 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
1002 } else if (clazz==int.class) {
1003 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
1004 } else if (clazz==float.class) {
1005 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
1006 } else if (clazz==long.class) {
1007 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
1008 } else if (clazz==double.class) {
1009 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
1013 public static void boxTo(MethodVisitor mv, Class<?> clazz) {
1014 if (clazz==Boolean.class) {
1015 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
1016 } else if (clazz==Character.class) {
1017 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
1018 } else if (clazz==Byte.class) {
1019 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
1020 } else if (clazz==Short.class) {
1021 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
1022 } else if (clazz==Integer.class) {
1023 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
1024 } else if (clazz==Float.class) {
1025 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
1026 } else if (clazz==Long.class) {
1027 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
1028 } else if (clazz==Double.class) {
1029 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
1033 public static void unboxFrom(MethodVisitor mv, Class<?> clazz) {
1034 if (clazz==Boolean.class) {
1035 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
1036 } else if (clazz==Character.class) {
1037 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C"); // C?
1038 } else if (clazz==Byte.class) {
1039 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B");
1040 } else if (clazz==Short.class) {
1041 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
1042 } else if (clazz==Integer.class) {
1043 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
1044 } else if (clazz==Float.class) {
1045 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
1046 } else if (clazz==Long.class) {
1047 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
1048 } else if (clazz==Double.class) {
1049 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
1054 public static String toClassCanonicalName(Class<?> clazz)
1056 return clazz.getName().replaceAll("\\.", "/");