in openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java [3765:3995]
private boolean writeIsDetachedMethod(ClassNode classNode, MethodNode meth) throws NoSuchMethodException {
InsnList instructions = meth.instructions;
// not detachable: return Boolean.FALSE
if (!_meta.isDetachable()) {
instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
"FALSE", Type.getDescriptor(Boolean.class)));
instructions.add(new InsnNode(Opcodes.ARETURN));
return false;
}
// if (sm != null)
// return (sm.isDetached ()) ? Boolean.TRUE : Boolean.FALSE;
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, SM, Type.getDescriptor(SMTYPE)));
LabelNode lblEndIfNull = new LabelNode();
instructions.add(new JumpInsnNode(Opcodes.IFNULL, lblEndIfNull));
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, SM, Type.getDescriptor(SMTYPE)));
instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
Type.getInternalName(SMTYPE),
"isDetached",
Type.getMethodDescriptor(Type.BOOLEAN_TYPE)));
LabelNode lblEndIfFalse = new LabelNode();
instructions.add(new JumpInsnNode(Opcodes.IFEQ, lblEndIfFalse));
instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
"TRUE", Type.getDescriptor(Boolean.class)));
instructions.add(new InsnNode(Opcodes.ARETURN));
instructions.add(lblEndIfFalse);
instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
"FALSE", Type.getDescriptor(Boolean.class)));
instructions.add(new InsnNode(Opcodes.ARETURN));
// END - if (sm != null)
// if we use detached state:
// if (pcGetDetachedState () != null
// && pcGetDetachedState != DESERIALIZED)
// return Boolean.TRUE;
Boolean state = _meta.usesDetachedState();
LabelNode lblNotDeser = null;
if (state != Boolean.FALSE) {
instructions.add(lblEndIfNull);
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
classNode.name,
PRE + "GetDetachedState",
Type.getMethodDescriptor(AsmHelper.TYPE_OBJECT)));
lblEndIfNull = new LabelNode();
instructions.add(new JumpInsnNode(Opcodes.IFNULL, lblEndIfNull));
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
classNode.name,
PRE + "GetDetachedState",
Type.getMethodDescriptor(AsmHelper.TYPE_OBJECT)));
instructions.add(new FieldInsnNode(Opcodes.GETSTATIC,
Type.getInternalName(PersistenceCapable.class),
"DESERIALIZED",
AsmHelper.TYPE_OBJECT.getDescriptor()));
lblNotDeser = new LabelNode();
instructions.add(new JumpInsnNode(Opcodes.IF_ACMPEQ, lblNotDeser));
instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
"TRUE", Type.getDescriptor(Boolean.class)));
instructions.add(new InsnNode(Opcodes.ARETURN));
if (state == Boolean.TRUE) {
// if we have to use detached state:
// return Boolean.FALSE;
instructions.add(lblEndIfNull);
instructions.add(lblNotDeser);
instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
"FALSE", Type.getDescriptor(Boolean.class)));
instructions.add(new InsnNode(Opcodes.ARETURN));
return false;
}
}
instructions.add(lblEndIfNull);
if (lblNotDeser != null) {
instructions.add(lblNotDeser);
}
// allow users with version or auto-assigned pk fields to manually
// construct a "detached" instance, so check these before taking into
// account non-existent detached state
// consider detached if version is non-default
FieldMetaData version = _meta.getVersionField();
if (state != Boolean.TRUE && version != null) {
// if (<version> != <default>)
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
addGetManagedValueCode(classNode, instructions, version, true);
LabelNode lblAfterDefault = ifDefaultValue(instructions, version);
// return true
instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
"TRUE", Type.getDescriptor(Boolean.class)));
instructions.add(new InsnNode(Opcodes.ARETURN));
instructions.add(lblAfterDefault);
if (!_addVersionInitFlag) {
// else return false;
instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
"FALSE", Type.getDescriptor(Boolean.class)));
instructions.add(new InsnNode(Opcodes.ARETURN));
}
else {
// if (pcVersionInit != false)
// return true
// else return null; // (returning null because we don't know the correct answer)
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
getfield(classNode, instructions, null, VERSION_INIT_STR, boolean.class);
LabelNode lblAfterEq = new LabelNode();
instructions.add(new JumpInsnNode(Opcodes.IFEQ, lblAfterEq));
instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
"TRUE", Type.getDescriptor(Boolean.class)));
instructions.add(new InsnNode(Opcodes.ARETURN));
instructions.add(lblAfterEq);
instructions.add(AsmHelper.getLoadConstantInsn(null));
instructions.add(new InsnNode(Opcodes.ARETURN));
}
return false;
}
// consider detached if auto-genned primary keys are non-default
LabelNode ifIns = null;
LabelNode ifIns2 = null;
if (state != Boolean.TRUE && _meta.getIdentityType() == ClassMetaData.ID_APPLICATION) {
// for each pk field:
// if (<pk> != <default> [&& !"".equals (<pk>)])
// return Boolean.TRUE;
FieldMetaData[] pks = _meta.getPrimaryKeyFields();
for (FieldMetaData pk : pks) {
if (pk.getValueStrategy() == ValueStrategies.NONE) {
continue;
}
if (ifIns != null) {
instructions.add(ifIns);
}
if (ifIns2 != null) {
instructions.add(ifIns2);
}
ifIns2 = null;
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
addGetManagedValueCode(classNode, instructions, pk, true);
ifIns = ifDefaultValue(instructions, pk);
if (pk.getDeclaredTypeCode() == JavaTypes.STRING) {
instructions.add(AsmHelper.getLoadConstantInsn(""));
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
addGetManagedValueCode(classNode, instructions, pk, true);
instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
Type.getInternalName(String.class),
"equals",
Type.getMethodDescriptor(Type.BOOLEAN_TYPE, AsmHelper.TYPE_OBJECT)));
ifIns2 = new LabelNode();
instructions.add(new JumpInsnNode(Opcodes.IFNE, ifIns2));
}
instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
"TRUE", Type.getDescriptor(Boolean.class)));
instructions.add(new InsnNode(Opcodes.ARETURN));
}
}
if (ifIns != null) {
instructions.add(ifIns);
}
if (ifIns2 != null) {
instructions.add(ifIns2);
}
// if detached state is not definitive, just give up now and return
// null so that the runtime will perform a DB lookup to determine
// whether we're detached or new
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
classNode.name,
ISDETACHEDSTATEDEFINITIVE,
Type.getMethodDescriptor(Type.BOOLEAN_TYPE)));
LabelNode lblAfterNe = new LabelNode();
instructions.add(new JumpInsnNode(Opcodes.IFNE, lblAfterNe));
instructions.add(AsmHelper.getLoadConstantInsn(null));
instructions.add(new InsnNode(Opcodes.ARETURN));
instructions.add(lblAfterNe);
// no detached state: if instance uses detached state and it's not
// synthetic or the instance is not serializable or the state isn't
// transient, must not be detached
if (state == null
&& (!ClassMetaData.SYNTHETIC.equals(_meta.getDetachedState())
|| !Serializable.class.isAssignableFrom(_meta.getDescribedType())
|| !_repos.getConfiguration().getDetachStateInstance().isDetachedStateTransient())) {
// return Boolean.FALSE
instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
"FALSE", Type.getDescriptor(Boolean.class)));
instructions.add(new InsnNode(Opcodes.ARETURN));
return true;
}
// no detached state: if instance uses detached state (and must be
// synthetic and transient in serializable instance at this point),
// not detached if state not set to DESERIALIZED
if (state == null) {
// if (pcGetDetachedState () == null) // instead of DESERIALIZED
// return Boolean.FALSE;
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
classNode.name,
PRE + "GetDetachedState",
Type.getMethodDescriptor(AsmHelper.TYPE_OBJECT)));
LabelNode lblIfNn = new LabelNode();
instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, lblIfNn));
instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(Boolean.class),
"FALSE", Type.getDescriptor(Boolean.class)));
instructions.add(new InsnNode(Opcodes.ARETURN));
instructions.add(lblIfNn);
}
// give up; we just don't know
instructions.add(AsmHelper.getLoadConstantInsn(null));
instructions.add(new InsnNode(Opcodes.ARETURN));
return true;
}