title: unboxing using the ASM Java library
body: <p>I'm using the ASM Java library to replace some reflection. I generate the body of this method:</p>
  
  <pre><code>void set(Object object, int fieldIndex, Object value);
  </code></pre>
  
  <p>With this generated method, I can set fields on an object at runtime without using reflection. It works great. However, I found it fails for primitive fields. Here is the relevant part of my set method:</p>
  
  <pre><code>for (int i = 0, n = cachedFields.length; i &lt; n; i++) {
      mv.visitLabel(labels[i]);
      mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
      mv.visitVarInsn(ALOAD, 1);
      mv.visitTypeInsn(CHECKCAST, targetClassName);
      mv.visitVarInsn(ALOAD, 3);
      Field field = cachedFields[i].field;
      Type fieldType = Type.getType(field.getType());
      mv.visitFieldInsn(PUTFIELD, targetClassName, field.getName(), fieldType.getDescriptor());
      mv.visitInsn(RETURN);
  }
  </code></pre>
  
  <p>This code is generating case labels for a select. It works great for objects but for primitives I get this error:</p>
  
  <blockquote>
    <p>Expecting to find float on stack</p>
  </blockquote>
  
  <p>Ok, that makes sense, I need to do the unboxing myself. I implemented the following:</p>
  
  <pre><code>for (int i = 0, n = cachedFields.length; i &lt; n; i++) {
      mv.visitLabel(labels[i]);
      mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
      mv.visitVarInsn(ALOAD, 1);
      mv.visitTypeInsn(CHECKCAST, targetClassName);
      mv.visitVarInsn(ALOAD, 3);
  
      Field field = cachedFields[i].field;
      Type fieldType = Type.getType(field.getType());
      switch (fieldType.getSort()) {
      case Type.BOOLEAN:
          mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
          mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
          break;
      case Type.BYTE:
          mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
          mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B");
          break;
      case Type.CHAR:
          mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
          mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
          break;
      case Type.SHORT:
          mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
          mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
          break;
      case Type.INT:
          mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
          mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
          break;
      case Type.FLOAT:
          mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
          mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
          break;
      case Type.LONG:
          mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
          mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
          break;
      case Type.DOUBLE:
          mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
          mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
          break;
      case Type.ARRAY:
          mv.visitTypeInsn(CHECKCAST, fieldType.getDescriptor());
          break;
      case Type.OBJECT:
          mv.visitTypeInsn(CHECKCAST, fieldType.getInternalName());
          break;
      }
  
      mv.visitFieldInsn(PUTFIELD, targetClassName, field.getName(), fieldType.getDescriptor());
      mv.visitInsn(RETURN);
  }
  </code></pre>
  
  <p>I have traced through and it definitely goes into "case Type.FLOAT" for the appropriate field, however, I get this error:</p>
  
  <blockquote>
    <p>Expecting to find object/array on stack</p>
  </blockquote>
  
  <p>This is where I'm stuck. For the life of me I can't figure out why the unboxing doesn't work. The "ALOAD, 3" is putting the third parameter of the set method on the stack, which should be a Float. Any ideas?</p>
  
  <p>I found the asm-commons library has a GeneratorAdapter class that has an unbox method. However, I don't really want to include yet another JAR for something that should be so simple. I looked at the GeneratorAdapter source and it is doing something very similar. I tried to modify my code to use GeneratorAdapter, just to see if it worked, but didn't find it at all easy to convert.</p>