You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by st...@apache.org on 2016/09/13 17:29:02 UTC
svn commit: r1760580 [2/5] - in /openjpa/branches/fb-3.0-asm:
openjpa-examples/openbooks/
openjpa-kernel/src/main/java/org/apache/openjpa/ant/
openjpa-kernel/src/main/java/org/apache/openjpa/conf/
openjpa-kernel/src/main/java/org/apache/openjpa/enhance...
Modified: openjpa/branches/fb-3.0-asm/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
URL: http://svn.apache.org/viewvc/openjpa/branches/fb-3.0-asm/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java?rev=1760580&r1=1760579&r2=1760580&view=diff
==============================================================================
--- openjpa/branches/fb-3.0-asm/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java (original)
+++ openjpa/branches/fb-3.0-asm/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java Tue Sep 13 17:29:01 2016
@@ -1,4745 +1,46 @@
/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package org.apache.openjpa.enhance;
-import java.io.Externalizable;
import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.ObjectInput;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutput;
-import java.io.ObjectOutputStream;
-import java.io.ObjectStreamClass;
-import java.io.Serializable;
-import java.io.ObjectStreamException;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.security.AccessController;
-import java.security.PrivilegedActionException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import org.apache.openjpa.lib.util.StringUtil;
import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.conf.OpenJPAConfigurationImpl;
import org.apache.openjpa.lib.conf.Configurations;
-import org.apache.openjpa.lib.log.Log;
-import org.apache.openjpa.lib.meta.ClassArgParser;
import org.apache.openjpa.lib.util.BytecodeWriter;
-import org.apache.openjpa.lib.util.ClassUtil;
import org.apache.openjpa.lib.util.Files;
-import org.apache.openjpa.lib.util.J2DoPrivHelper;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.lib.util.Options;
-import org.apache.openjpa.lib.util.Services;
-import org.apache.openjpa.lib.util.Localizer.Message;
-import org.apache.openjpa.lib.util.svn.SVNUtils;
-import org.apache.openjpa.meta.AccessCode;
-import org.apache.openjpa.meta.ClassMetaData;
-import org.apache.openjpa.meta.FieldMetaData;
-import org.apache.openjpa.meta.JavaTypes;
-import org.apache.openjpa.meta.MetaDataRepository;
-import org.apache.openjpa.meta.ValueStrategies;
-import org.apache.openjpa.util.ApplicationIds;
-import org.apache.openjpa.util.GeneralException;
-import org.apache.openjpa.util.InternalException;
-import org.apache.openjpa.util.BigDecimalId;
-import org.apache.openjpa.util.BigIntegerId;
-import org.apache.openjpa.util.ByteId;
-import org.apache.openjpa.util.CharId;
-import org.apache.openjpa.util.DateId;
-import org.apache.openjpa.util.DoubleId;
-import org.apache.openjpa.util.Id;
-import org.apache.openjpa.util.IntId;
-import org.apache.openjpa.util.FloatId;
-import org.apache.openjpa.util.LongId;
-import org.apache.openjpa.util.ObjectId;
-import org.apache.openjpa.util.ShortId;
-import org.apache.openjpa.util.StringId;
-import org.apache.openjpa.util.OpenJPAException;
-import org.apache.openjpa.util.UserException;
-import org.apache.openjpa.util.ImplHelper;
-import serp.bytecode.BCClass;
-import serp.bytecode.BCField;
-import serp.bytecode.BCMethod;
-import serp.bytecode.Code;
-import serp.bytecode.Constants;
-import serp.bytecode.Exceptions;
-import serp.bytecode.FieldInstruction;
-import serp.bytecode.GetFieldInstruction;
-import serp.bytecode.IfInstruction;
-import serp.bytecode.Instruction;
-import serp.bytecode.JumpInstruction;
-import serp.bytecode.LoadInstruction;
-import serp.bytecode.LookupSwitchInstruction;
-import serp.bytecode.MethodInstruction;
-import serp.bytecode.Project;
-import serp.bytecode.PutFieldInstruction;
-import serp.bytecode.TableSwitchInstruction;
-import serp.bytecode.ClassInstruction;
-/**
- * Bytecode enhancer used to enhance persistent classes from metadata. The
- * enhancer must be invoked on all persistence-capable and persistence aware
- * classes.
- *
- * @author Abe White
- */
-public class PCEnhancer {
- // Designates a version for maintaining compatbility when PCEnhancer
- // modifies enhancement that can break serialization or other contracts
- // Each enhanced class will return the value of this field via
- // public int getEnhancementContractVersion()
- public static final int ENHANCER_VERSION;
-
- boolean _addVersionInitFlag = true;
-
- public static final int ENHANCE_NONE = 0;
- public static final int ENHANCE_AWARE = 2 << 0;
- public static final int ENHANCE_INTERFACE = 2 << 1;
- public static final int ENHANCE_PC = 2 << 2;
-
- public static final String PRE = "pc";
- public static final String ISDETACHEDSTATEDEFINITIVE = PRE
- + "isDetachedStateDefinitive";
-
- private static final Class PCTYPE = PersistenceCapable.class;
- private static final String SM = PRE + "StateManager";
- private static final Class SMTYPE = StateManager.class;
- private static final String INHERIT = PRE + "InheritedFieldCount";
- private static final String CONTEXTNAME = "GenericContext";
- private static final Class USEREXCEP = UserException.class;
- private static final Class INTERNEXCEP = InternalException.class;
- private static final Class HELPERTYPE = PCRegistry.class;
- private static final String SUPER = PRE + "PCSuperclass";
- private static final Class OIDFSTYPE = FieldSupplier.class;
- private static final Class OIDFCTYPE = FieldConsumer.class;
-
- private static final String VERSION_INIT_STR = PRE + "VersionInit";
-
- private static final Localizer _loc = Localizer.forPackage
- (PCEnhancer.class);
- private static final String REDEFINED_ATTRIBUTE
- = PCEnhancer.class.getName() + "#redefined-type";
-
- private static final AuxiliaryEnhancer[] _auxEnhancers;
- static {
- Class[] classes = Services.getImplementorClasses(
- AuxiliaryEnhancer.class,
- AccessController.doPrivileged(
- J2DoPrivHelper.getClassLoaderAction(AuxiliaryEnhancer.class)));
- List auxEnhancers = new ArrayList(classes.length);
- for (int i = 0; i < classes.length; i++) {
- try {
- auxEnhancers.add(AccessController.doPrivileged(
- J2DoPrivHelper.newInstanceAction(classes[i])));
- } catch (Throwable t) {
- // aux enhancer may rely on non-existant spec classes, etc
- }
- }
- _auxEnhancers = (AuxiliaryEnhancer[]) auxEnhancers.toArray
- (new AuxiliaryEnhancer[auxEnhancers.size()]);
-
- int rev = 0;
- Properties revisionProps = new Properties();
- try {
- InputStream in = PCEnhancer.class.getResourceAsStream("/META-INF/org.apache.openjpa.revision.properties");
- if (in != null) {
- try {
- revisionProps.load(in);
- } finally {
- in.close();
- }
- }
- String prop = revisionProps.getProperty("openjpa.enhancer.revision");
- rev = SVNUtils.svnInfoToInteger(prop);
- } catch (Exception e) {
- }
- if (rev > 0) {
- ENHANCER_VERSION = rev;
- } else {
- // Something bad happened and we couldn't load from the properties file. We need to default to using the
- // value of 2 because that is the value that was the value as of rev.511998.
- ENHANCER_VERSION = 2;
- }
- }
-
- private BCClass _pc;
- private final BCClass _managedType;
- private final MetaDataRepository _repos;
- private final ClassMetaData _meta;
- private final Log _log;
- private Collection _oids = null;
- private boolean _defCons = true;
- private boolean _redefine = false;
- private boolean _subclass = false;
- private boolean _fail = false;
- private Set _violations = null;
- private File _dir = null;
- private BytecodeWriter _writer = null;
- private Map _backingFields = null; // map of set / get names => field names
- private Map _attrsToFields = null; // map of attr names => field names
- private Map _fieldsToAttrs = null; // map of field names => attr names
- private boolean _isAlreadyRedefined = false;
- private boolean _isAlreadySubclassed = false;
- private boolean _bcsConfigured = false;
-
- private boolean _optimizeIdCopy = false; // whether to attempt optimizing id copy
-
- /**
- * Constructor. Supply configuration and type to enhance. This will look
- * up the metadata for <code>type</code> from <code>conf</code>'s
- * repository.
- */
- public PCEnhancer(OpenJPAConfiguration conf, Class type) {
- this(conf, AccessController.doPrivileged(J2DoPrivHelper
- .loadProjectClassAction(new Project(), type)),
- (MetaDataRepository) null);
- }
-
- /**
- * Constructor. Supply configuration and type to enhance. This will look
- * up the metadata for <code>meta</code> by converting back to a class
- * and then loading from <code>conf</code>'s repository.
- */
- public PCEnhancer(OpenJPAConfiguration conf, ClassMetaData meta) {
- this(conf, AccessController.doPrivileged(J2DoPrivHelper
- .loadProjectClassAction(new Project(), meta.getDescribedType())),
- meta.getRepository());
- }
-
- /**
- * Constructor. Supply configuration.
- *
- * @param type the bytecode representation fo the type to
- * enhance; this can be created from any stream or file
- * @param repos a metadata repository to use for metadata access,
- * or null to create a new reporitory; the repository
- * from the given configuration isn't used by default
- * because the configuration might be an
- * implementation-specific subclass whose metadata
- * required more than just base metadata files
- * @deprecated use {@link #PCEnhancer(OpenJPAConfiguration, BCClass,
- MetaDataRepository, ClassLoader)} instead.
- */
- public PCEnhancer(OpenJPAConfiguration conf, BCClass type,
- MetaDataRepository repos) {
- this(conf, type, repos, null);
- }
-
- /**
- * Constructor. Supply configuration.
- *
- * @param type the bytecode representation fo the type to
- * enhance; this can be created from any stream or file
- * @param repos a metadata repository to use for metadata access,
- * or null to create a new reporitory; the repository
- * from the given configuration isn't used by default
- * because the configuration might be an
- * implementation-specific subclass whose metadata
- * required more than just base metadata files
- * @param loader the environment classloader to use for loading
- * classes and resources.
- */
- public PCEnhancer(OpenJPAConfiguration conf, BCClass type,
- MetaDataRepository repos, ClassLoader loader) {
- _managedType = type;
- _pc = type;
-
- _log = conf.getLog(OpenJPAConfiguration.LOG_ENHANCE);
-
- if (repos == null) {
- _repos = conf.newMetaDataRepositoryInstance();
- _repos.setSourceMode(MetaDataRepository.MODE_META);
- } else
- _repos = repos;
- _meta = _repos.getMetaData(type.getType(), loader, false);
-
- configureOptimizeIdCopy();
- }
-
- /**
- * Constructor. Supply repository. The repository's configuration will
- * be used, and the metadata passed in will be used as-is without doing
- * any additional lookups. This is useful when running the enhancer
- * during metadata load.
- *
- * @param repos a metadata repository to use for metadata access,
- * or null to create a new reporitory; the repository
- * from the given configuration isn't used by default
- * because the configuration might be an
- * implementation-specific subclass whose metadata
- * required more than just base metadata files
- * @param type the bytecode representation fo the type to
- * enhance; this can be created from any stream or file
- * @param meta the metadata to use for processing this type.
- *
- * @since 1.1.0
- */
- public PCEnhancer(MetaDataRepository repos, BCClass type,
- ClassMetaData meta) {
- _managedType = type;
- _pc = type;
-
- _log = repos.getConfiguration()
- .getLog(OpenJPAConfiguration.LOG_ENHANCE);
-
- _repos = repos;
- _meta = meta;
- }
-
- static String toPCSubclassName(Class cls) {
- return ClassUtil.getPackageName(PCEnhancer.class) + "."
- + cls.getName().replace('.', '$') + "$pcsubclass";
- }
-
- /**
- * Whether or not <code>className</code> is the name for a
- * dynamically-created persistence-capable subclass.
- *
- * @since 1.1.0
- */
- public static boolean isPCSubclassName(String className) {
- return className.startsWith(ClassUtil.getPackageName(PCEnhancer.class))
- && className.endsWith("$pcsubclass");
- }
-
- /**
- * If <code>className</code> is a dynamically-created persistence-capable
- * subclass name, returns the name of the class that it subclasses.
- * Otherwise, returns <code>className</code>.
- *
- * @since 1.1.0
- */
- public static String toManagedTypeName(String className) {
- if (isPCSubclassName(className)) {
- className = className.substring(
- ClassUtil.getPackageName(PCEnhancer.class).length() + 1);
- className = className.substring(0, className.lastIndexOf("$"));
- // this is not correct for nested PCs
- className = className.replace('$', '.');
- }
-
- return className;
- }
-
- /**
- * Constructor. Supply configuration, type, and metadata.
- */
- public PCEnhancer(OpenJPAConfiguration conf, BCClass type,
- ClassMetaData meta) {
- this(conf, type, meta.getRepository());
- }
-
- /**
- * Return the bytecode representation of the persistence-capable class
- * being manipulated.
- */
- public BCClass getPCBytecode() {
- return _pc;
- }
-
- /**
- * Return the bytecode representation of the managed class being
- * manipulated. This is usually the same as {@link #getPCBytecode},
- * except when running the enhancer to redefine and subclass
- * existing persistent types.
- */
- public BCClass getManagedTypeBytecode() {
- return _managedType;
- }
-
- /**
- * Return the metadata for the class being manipulated, or null if not
- * a persistent type.
- */
- public ClassMetaData getMetaData() {
- return _meta;
- }
-
- /**
- * A boolean indicating whether the enhancer should add a no-args
- * constructor if one is not already present in the class. OpenJPA
- * requires that a no-arg constructor (whether created by the compiler
- * or by the user) be present in a PC.
- */
- public boolean getAddDefaultConstructor() {
- return _defCons;
- }
-
- /**
- * A boolean indicating whether the enhancer should add a no-args
- * constructor if one is not already present in the class. OpenJPA
- * requires that a no-arg constructor (whether created by the compiler
- * or by the user) be present in a PC.
- */
- public void setAddDefaultConstructor(boolean addDefaultConstructor) {
- _defCons = addDefaultConstructor;
- }
-
- /**
- * Whether the enhancer should mutate its arguments, or just run validation
- * and optional subclassing logic on them. Usually used in conjunction with
- * <code>setCreateSubclass(true)</code>.
- *
- * @since 1.0.0
- */
- public boolean getRedefine() {
- return _redefine;
- }
-
- /**
- * Whether the enhancer should mutate its arguments, or just run validation
- * and optional subclassing logic on them. Usually used in conjunction with
- * <code>setCreateSubclass(true)</code>.
- *
- * @since 1.0.0
- */
- public void setRedefine(boolean redefine) {
- _redefine = redefine;
- }
-
- /**
- * Whether the type that this instance is enhancing has already been
- * redefined.
- *
- * @since 1.0.0
- */
- public boolean isAlreadyRedefined() {
- return _isAlreadyRedefined;
- }
-
- /**
- * Whether the type that this instance is enhancing has already been
- * subclassed in this instance's environment classloader.
- *
- * @since 1.0.0
- */
- public boolean isAlreadySubclassed() {
- return _isAlreadySubclassed;
- }
-
- /**
- * Whether the enhancer should make its arguments persistence-capable,
- * or generate a persistence-capable subclass.
- *
- * @since 1.0.0
- */
- public boolean getCreateSubclass() {
- return _subclass;
- }
-
- /**
- * Whether the enhancer should make its arguments persistence-capable,
- * or generate a persistence-capable subclass.
- *
- * @since 1.0.0
- */
- public void setCreateSubclass(boolean subclass) {
- _subclass = subclass;
- _addVersionInitFlag = false;
- }
-
- /**
- * Whether to fail if the persistent type uses property access and
- * bytecode analysis shows that it may be violating OpenJPA's property
- * access restrictions.
- */
- public boolean getEnforcePropertyRestrictions() {
- return _fail;
- }
-
- /**
- * Whether to fail if the persistent type uses property access and
- * bytecode analysis shows that it may be violating OpenJPA's property
- * access restrictions.
- */
- public void setEnforcePropertyRestrictions(boolean fail) {
- _fail = fail;
- }
-
- /**
- * The base build directory to generate code to. The proper package
- * structure will be created beneath this directory. Defaults to
- * overwriting the existing class file if null.
- */
- public File getDirectory() {
- return _dir;
- }
-
- /**
- * The base build directory to generate code to. The proper package
- * structure will be creaed beneath this directory. Defaults to
- * overwriting the existing class file if null.
- */
- public void setDirectory(File dir) {
- _dir = dir;
- }
-
- /**
- * Return the current {@link BytecodeWriter} to write to or null if none.
- */
- public BytecodeWriter getBytecodeWriter() {
- return _writer;
- }
-
- /**
- * Set the {@link BytecodeWriter} to write the bytecode to or null if none.
- */
- public void setBytecodeWriter(BytecodeWriter writer) {
- _writer = writer;
- }
-
- /**
- * Perform bytecode enhancements.
- *
- * @return <code>ENHANCE_*</code> constant
- */
- public int run() {
- Class<?> type = _managedType.getType();
- try {
- // if managed interface, skip
- if (_pc.isInterface())
- return ENHANCE_INTERFACE;
-
- // check if already enhanced
- ClassLoader loader = AccessController.doPrivileged(J2DoPrivHelper.getClassLoaderAction(type));
- for (String iface : _managedType.getDeclaredInterfaceNames()) {
- if (iface.equals(PCTYPE.getName())) {
- if (_log.isTraceEnabled()) {
- _log.trace(_loc.get("pc-type", type, loader));
- }
- return ENHANCE_NONE;
- }
- }
- if (_log.isTraceEnabled()) {
- _log.trace(_loc.get("enhance-start", type, loader));
- }
-
-
- configureBCs();
-
- // validate properties before replacing field access so that
- // we build up a record of backing fields, etc
- if (isPropertyAccess(_meta)) {
- validateProperties();
- if (getCreateSubclass())
- addAttributeTranslation();
- }
- replaceAndValidateFieldAccess();
- processViolations();
-
- if (_meta != null) {
- enhanceClass();
- addFields();
- addStaticInitializer();
- addPCMethods();
- addAccessors();
- addAttachDetachCode();
- addSerializationCode();
- addCloningCode();
- runAuxiliaryEnhancers();
- return ENHANCE_PC;
- }
- return ENHANCE_AWARE;
- } catch (OpenJPAException ke) {
- throw ke;
- } catch (Exception e) {
- throw new GeneralException(_loc.get("enhance-error",
- type.getName(), e.getMessage()), e);
- }
- }
-
- private void configureBCs() {
- if (!_bcsConfigured) {
- if (getRedefine()) {
- if (_managedType.getAttribute(REDEFINED_ATTRIBUTE) == null)
- _managedType.addAttribute(REDEFINED_ATTRIBUTE);
- else
- _isAlreadyRedefined = true;
- }
-
- if (getCreateSubclass()) {
- PCSubclassValidator val = new PCSubclassValidator(
- _meta, _managedType, _log, _fail);
- val.assertCanSubclass();
-
- _pc = _managedType.getProject().loadClass(
- toPCSubclassName(_managedType.getType()));
- if (_pc.getSuperclassBC() != _managedType) {
- _pc.setSuperclass(_managedType);
- _pc.setAbstract(_managedType.isAbstract());
- _pc.declareInterface(DynamicPersistenceCapable.class);
- } else {
- _isAlreadySubclassed = true;
- }
- }
-
- _bcsConfigured = true;
- }
- }
-
- /**
- * Write the generated bytecode.
- */
- public void record()
- throws IOException {
- if (_managedType != _pc && getRedefine())
- record(_managedType);
- record(_pc);
- if (_oids != null)
- for (Iterator itr = _oids.iterator(); itr.hasNext();)
- record((BCClass) itr.next());
- }
-
- /**
- * Write the given class.
- */
- private void record(BCClass bc)
- throws IOException {
- if (_writer != null)
- _writer.write(bc);
- else if (_dir == null)
- AsmAdaptor.write(bc);
- else {
- File dir = Files.getPackageFile(_dir, bc.getPackageName(), true);
- AsmAdaptor.write(bc, new File(dir, bc.getClassName() + ".class"));
- }
- }
-
- /**
- * Validate that the methods that use a property-access instance are
- * written correctly. This method also gathers information on each
- * property's backing field.
- */
- private void validateProperties() {
- FieldMetaData[] fmds;
- if (getCreateSubclass())
- fmds = _meta.getFields();
- else
- fmds = _meta.getDeclaredFields();
- Method meth;
- BCMethod getter, setter;
- BCField returned, assigned = null;
- for (int i = 0; i < fmds.length; i++) {
-
- if (!(fmds[i].getBackingMember() instanceof Method) ) {
- // If not mixed access is not defined, flag the field members,
- // otherwise do not process them because they are valid
- // persistent attributes.
- if (!_meta.isMixedAccess()) {
- addViolation("property-bad-member",
- new Object[]{ fmds[i], fmds[i].getBackingMember() },
- true);
- }
- continue;
- }
-
- meth = (Method) fmds[i].getBackingMember();
- // ##### this will fail if we override and don't call super.
- BCClass declaringType = _managedType.getProject()
- .loadClass(fmds[i].getDeclaringType());
- getter = declaringType.getDeclaredMethod(meth.getName(),
- meth.getParameterTypes());
- if (getter == null) {
- addViolation("property-no-getter", new Object[]{ fmds[i] },
- true);
- continue;
- }
- returned = getReturnedField(getter);
- if (returned != null)
- registerBackingFieldInfo(fmds[i], getter, returned);
-
- setter = declaringType.getDeclaredMethod(getSetterName(fmds[i]),
- new Class[]{ fmds[i].getDeclaredType() });
- if (setter == null) {
- if (returned == null) {
- addViolation("property-no-setter",
- new Object[]{ fmds[i] }, true);
- continue;
- } else if (!getRedefine()) {
- // create synthetic setter
- setter = _managedType.declareMethod(getSetterName(fmds[i]),
- void.class, new Class[]{ fmds[i].getDeclaredType() });
- setter.makePrivate();
- Code code = setter.getCode(true);
- code.aload().setThis();
- code.xload().setParam(0);
- code.putfield().setField(returned);
- code.vreturn();
- code.calculateMaxStack();
- code.calculateMaxLocals();
- }
- }
-
- if (setter != null)
- assigned = getAssignedField(setter);
-
- if (assigned != null) {
- if (setter != null)
- registerBackingFieldInfo(fmds[i], setter, assigned);
-
- if (assigned != returned)
- addViolation("property-setter-getter-mismatch", new Object[]
- { fmds[i], assigned.getName(), (returned == null)
- ? null : returned.getName() }, false);
- }
- }
- }
-
- private void registerBackingFieldInfo(FieldMetaData fmd, BCMethod method,
- BCField field) {
- if (_backingFields == null)
- _backingFields = new HashMap();
- _backingFields.put(method.getName(), field.getName());
-
- if (_attrsToFields == null)
- _attrsToFields = new HashMap();
- _attrsToFields.put(fmd.getName(), field.getName());
-
- if (_fieldsToAttrs == null)
- _fieldsToAttrs = new HashMap();
- _fieldsToAttrs.put(field.getName(), fmd.getName());
- }
-
- private void addAttributeTranslation() {
-
- // Get all field metadata
- ArrayList<Integer> propFmds = new ArrayList<Integer>();
- FieldMetaData[] fmds = _meta.getFields();
-
- if (_meta.isMixedAccess()) {
- // Stores indexes of property access fields to be used in
- //
- propFmds = new ArrayList<Integer>();
-
- // Determine which fields have property access and save their
- // indexes
- for (int i = 0; i < fmds.length; i++) {
- if (isPropertyAccess(fmds[i]))
- propFmds.add(i);
- }
-
- // if no fields have property access do not do attribute translation
- if (propFmds.size() == 0)
- return;
- }
-
- _pc.declareInterface(AttributeTranslator.class);
- BCMethod method = _pc.declareMethod(PRE + "AttributeIndexToFieldName",
- String.class, new Class[] { int.class });
- method.makePublic();
- Code code = method.getCode(true);
-
- // switch (val)
- code.iload().setParam(0);
- if (!_meta.isMixedAccess()) {
- // if not mixed access use a table switch on all property-based fmd.
- // a table switch is more efficient with +1 incremental operations
- TableSwitchInstruction tabins = code.tableswitch();
-
- tabins.setLow(0);
- tabins.setHigh(fmds.length - 1);
-
- // case i:
- // return <_attrsToFields.get(fmds[i].getName())>
- for (int i = 0; i < fmds.length; i++) {
- tabins.addTarget(code.constant().setValue(
- _attrsToFields.get(fmds[i].getName())));
- code.areturn();
- }
- // default: throw new IllegalArgumentException ()
- tabins.setDefaultTarget(throwException
- (code, IllegalArgumentException.class));
- }
- else {
- // In mixed access mode, property indexes are not +1 incremental
- // a lookup switch must be used to do indexed lookup.
- LookupSwitchInstruction lookupins = code.lookupswitch();
-
- for (Integer i : propFmds) {
- lookupins.addCase(i,
- code.constant().setValue(
- _attrsToFields.get(fmds[i].getName())));
- code.areturn();
- }
- // default: throw new IllegalArgumentException ()
- lookupins.setDefaultTarget(throwException
- (code, IllegalArgumentException.class));
- }
-
- code.calculateMaxLocals();
- code.calculateMaxStack();
- }
-
- /**
- * Return the name of the setter method for the given field.
- */
- private static String getSetterName(FieldMetaData fmd) {
- return fmd.getSetterName();
- }
-
- /**
- * Return the field returned by the given method, or null if none.
- * Package-protected and static for testing.
- */
- static BCField getReturnedField(BCMethod meth) {
- return findField(meth, (AccessController.doPrivileged(
- J2DoPrivHelper.newCodeAction())).xreturn()
- .setType(meth.getReturnType()), false);
- }
-
- /**
- * Return the field assigned in the given method, or null if none.
- * Package-protected and static for testing.
- */
- static BCField getAssignedField(BCMethod meth) {
- return findField(meth, (AccessController.doPrivileged(
- J2DoPrivHelper.newCodeAction())).putfield(), true);
- }
-
- /**
- * Return the field returned / assigned by <code>meth</code>. Returns
- * null if non-fields (methods, literals, parameters, variables) are
- * returned, or if non-parameters are assigned to fields.
- */
- private static BCField findField(BCMethod meth, Instruction template,
- boolean findAccessed) {
- // ignore any static methods. OpenJPA only currently supports
- // non-static setters and getters
- if (meth.isStatic())
- return null;
-
- Code code = meth.getCode(false);
- if (code == null)
- return null;
- code.beforeFirst();
-
- BCField field = null, cur;
- Instruction templateIns, prevIns, earlierIns;
- while (code.searchForward(template)) {
- int backupCount = 3;
- templateIns = code.previous();
- if (!code.hasPrevious())
- return null;
- prevIns = code.previous();
-
- if (prevIns instanceof ClassInstruction
- && code.hasPrevious()) {
- prevIns = code.previous();
- backupCount++;
- }
-
- if (!code.hasPrevious())
- return null;
- earlierIns = code.previous();
-
- // if the opcode two before the template was an aload_0, check
- // against the middle instruction based on what type of find
- // we're doing
- if (!(earlierIns instanceof LoadInstruction)
- || !((LoadInstruction) earlierIns).isThis())
- return null;
-
- // if the middle instruction was a getfield, then it's the
- // field that's being accessed
- if (!findAccessed && prevIns instanceof GetFieldInstruction) {
- final FieldInstruction fPrevIns = (FieldInstruction) prevIns;
- cur = AccessController.doPrivileged(
- J2DoPrivHelper.getFieldInstructionFieldAction(fPrevIns));
- // if the middle instruction was an xload_1, then the
- // matched instruction is the field that's being set.
- } else if (findAccessed && prevIns instanceof LoadInstruction
- && ((LoadInstruction) prevIns).getParam() == 0) {
- final FieldInstruction fTemplateIns =
- (FieldInstruction) templateIns;
- cur = AccessController.doPrivileged(J2DoPrivHelper
- .getFieldInstructionFieldAction(fTemplateIns));
- } else
- return null;
-
- if (field != null && cur != field)
- return null;
- field = cur;
-
- // ready for next search iteration
- while (backupCount > 0) {
- code.next();
- backupCount--;
- }
- }
- return field;
- }
-
- /**
- * Record a violation of the property access restrictions.
- */
- private void addViolation(String key, Object[] args, boolean fatal) {
- if (_violations == null)
- _violations = new HashSet();
- _violations.add(_loc.get(key, args));
- _fail |= fatal;
- }
-
- /**
- * Log / throw recorded property access violations.
- */
- private void processViolations() {
- if (_violations == null)
- return;
-
- String sep = J2DoPrivHelper.getLineSeparator();
- StringBuilder buf = new StringBuilder();
- for (Iterator itr = _violations.iterator(); itr.hasNext();) {
- buf.append(itr.next());
- if (itr.hasNext())
- buf.append(sep);
- }
- Message msg = _loc.get("property-violations", buf);
-
- if (_fail)
- throw new UserException(msg);
- if (_log.isWarnEnabled())
- _log.warn(msg);
- }
-
- /**
- * Replaced all direct access to managed fields with the appropriate
- * pcGet/pcSet method. Note that this includes access to fields
- * owned by PersistenceCapable classes other than this one.
- */
- private void replaceAndValidateFieldAccess() throws NoSuchMethodException {
- // create template putfield/getfield instructions to search for
- Code template = AccessController.doPrivileged(
- J2DoPrivHelper.newCodeAction());
- Instruction put = template.putfield();
- Instruction get = template.getfield();
- Instruction stat = template.invokestatic();
-
- // look through all methods; this is done before any methods are added
- // so we don't need to worry about excluding synthetic methods.
- BCMethod[] methods = _managedType.getDeclaredMethods();
- Code code;
- for (int i = 0; i < methods.length; i++) {
- code = methods[i].getCode(false);
-
- // don't modify the methods specified by the auxiliary enhancers
- if (code != null && !skipEnhance(methods[i])) {
- replaceAndValidateFieldAccess(code, get, true, stat);
- replaceAndValidateFieldAccess(code, put, false, stat);
- }
- }
- }
-
- /**
- * Replaces all instructions matching the given template in the given
- * code block with calls to the appropriate generated getter/setter.
- *
- * @param code the code block to modify; the code iterator will
- * be placed before the first instruction on method start,
- * and will be after the last instruction on method completion
- * @param ins the template instruction to search for; either a
- * getfield or putfield instruction
- * @param get boolean indicating if this is a get instruction
- * @param stat template invokestatic instruction to replace with
- */
- private void replaceAndValidateFieldAccess(Code code, Instruction ins,
- boolean get, Instruction stat) throws NoSuchMethodException {
- code.beforeFirst();
-
- FieldInstruction fi;
- MethodInstruction mi;
- ClassMetaData owner;
- String name, typeName, methodName;
- while (code.searchForward(ins)) {
- // back up to the matched instruction
- fi = (FieldInstruction) code.previous();
- name = fi.getFieldName();
- typeName = fi.getFieldTypeName();
- owner = getPersistenceCapableOwner(name, fi.getFieldDeclarerType());
- FieldMetaData fmd = owner == null ? null : owner.getField(name);
- if (isPropertyAccess(fmd)) {
- // if we're directly accessing a field in another class
- // hierarchy that uses property access, something is wrong
- if (owner != _meta && owner.getDeclaredField(name) != null &&
- _meta != null && !owner.getDescribedType()
- .isAssignableFrom(_meta.getDescribedType()))
- throw new UserException(_loc.get("property-field-access",
- new Object[]{ _meta, owner, name,
- code.getMethod().getName() }));
-
- // if we're directly accessing a property-backing field outside
- // the property in our own class, notify user
- if (isBackingFieldOfAnotherProperty(name, code))
- addViolation("property-field-access", new Object[]{ _meta,
- owner, name, code.getMethod().getName() }, false);
- }
-
- if (owner == null ||
- owner.getDeclaredField(fromBackingFieldName(name)) == null) {
- // not persistent field?
- code.next();
- continue;
- } else if (!getRedefine() && !getCreateSubclass()
- && isFieldAccess(fmd)) {
- // replace the instruction with a call to the generated access
- // method
- mi = (MethodInstruction) code.set(stat);
-
- // invoke the proper access method, whether getter or setter
- String prefix = (get) ? PRE + "Get" : PRE + "Set";
- methodName = prefix + name;
- if (get) {
- mi.setMethod(getType(owner).getName(),
- methodName, typeName, new String[]
- { getType(owner).getName() });
- } else {
- mi.setMethod(getType(owner).getName(),
- methodName, "void", new String[]
- { getType(owner).getName(), typeName });
- }
- code.next();
- } else if (getRedefine()) {
- name = fromBackingFieldName(name);
- if (get) {
- addNotifyAccess(code, owner.getField(name));
- code.next();
- } else {
- // insert the set operations after the field mutation, but
- // first load the old value for use in the
- // StateManager.settingXXX method.
- loadManagedInstance(code, false);
- final FieldInstruction fFi = fi;
- code.getfield().setField(
- AccessController.doPrivileged(J2DoPrivHelper
- .getFieldInstructionFieldAction(fFi)));
- int val = code.getNextLocalsIndex();
- code.xstore().setLocal(val).setType(fi.getFieldType());
-
- // move past the putfield
- code.next();
- addNotifyMutation(code, owner.getField(name), val, -1);
- }
- } else {
- code.next();
- }
- code.calculateMaxLocals();
- code.calculateMaxStack();
- }
- }
-
- private void addNotifyAccess(Code code, FieldMetaData fmd) {
- // PCHelper.accessingField(this, <absolute-index>);
- code.aload().setThis();
- code.constant().setValue(fmd.getIndex());
- code.invokestatic().setMethod(RedefinitionHelper.class,
- "accessingField", void.class,
- new Class[] { Object.class, int.class });
- }
-
- /**
- * This must be called after setting the value in the object.
- *
- * @param val the position in the local variable table where the
- * old value is stored
- * @param param the parameter position containing the new value, or
- * -1 if the new value is unavailable and should therefore be looked
- * up.
- * @throws NoSuchMethodException
- */
- private void addNotifyMutation(Code code, FieldMetaData fmd, int val,
- int param)
- throws NoSuchMethodException {
- // PCHelper.settingField(this, <absolute-index>, old, new);
- code.aload().setThis();
- code.constant().setValue(fmd.getIndex());
- Class type = fmd.getDeclaredType();
- // we only have special signatures for primitives and Strings
- if (!type.isPrimitive() && type != String.class)
- type = Object.class;
- code.xload().setLocal(val).setType(type);
- if (param == -1) {
- loadManagedInstance(code, false);
- addGetManagedValueCode(code, fmd);
- } else {
- code.xload().setParam(param).setType(type);
- }
- code.invokestatic().setMethod(RedefinitionHelper.class, "settingField",
- void.class, new Class[] {
- Object.class, int.class, type, type
- });
- }
-
- /**
- * Return true if the given instruction accesses a field that is a backing
- * field of another property in this property-access class.
- */
- private boolean isBackingFieldOfAnotherProperty(String name, Code code) {
- String methName = code.getMethod().getName();
- return !"<init>".equals(methName)
- && _backingFields != null
- && !name.equals(_backingFields.get(methName))
- && _backingFields.containsValue(name);
- }
-
- /**
- * Helper method to return the declaring PersistenceCapable class of
- * the given field.
- *
- * @param fieldName the name of the field
- * @param owner the nominal owner of the field
- * @return the metadata for the PersistenceCapable type that
- * declares the field (and therefore has the static method), or null if none
- */
- private ClassMetaData getPersistenceCapableOwner(String fieldName,
- Class owner) {
- // find the actual ancestor class that declares the field, then
- // check if the class is persistent, and if the field is managed
- Field f = Reflection.findField(owner, fieldName, false);
- if (f == null)
- return null;
-
- // managed interface
- if (_meta != null && _meta.getDescribedType().isInterface())
- return _meta;
-
- return _repos.getMetaData(f.getDeclaringClass(), null, false);
- }
-
- /**
- * Adds all synthetic methods to the bytecode by delegating to
- * the various addXXXMethods () functions in this class. Includes
- * all static field access methods.
- * Note that the 'stock' methods like <code>pcIsTransactional</code>,
- * <code>pcFetchObjectId</code>, etc are defined only in the
- * least-derived PersistenceCapable type.
- */
- private void addPCMethods()
- throws NoSuchMethodException {
- addClearFieldsMethod();
- addNewInstanceMethod(true);
- addNewInstanceMethod(false);
- addManagedFieldCountMethod();
- addReplaceFieldsMethods();
- addProvideFieldsMethods();
- addCopyFieldsMethod();
-
- if (_meta.getPCSuperclass() == null || getCreateSubclass()) {
- addStockMethods();
- addGetVersionMethod();
- addReplaceStateManagerMethod();
-
- if (_meta.getIdentityType() != ClassMetaData.ID_APPLICATION)
- addNoOpApplicationIdentityMethods();
- }
-
- // add the app id methods to each subclass rather
- // than just the superclass, since it is possible to have
- // a subclass with an app id hierarchy that matches the
- // persistent class inheritance hierarchy
- if (_meta.getIdentityType() == ClassMetaData.ID_APPLICATION
- && (_meta.getPCSuperclass() == null || getCreateSubclass() ||
- _meta.getObjectIdType() !=
- _meta.getPCSuperclassMetaData().getObjectIdType())) {
- addCopyKeyFieldsToObjectIdMethod(true);
- addCopyKeyFieldsToObjectIdMethod(false);
- addCopyKeyFieldsFromObjectIdMethod(true);
- addCopyKeyFieldsFromObjectIdMethod(false);
- if (_meta.hasAbstractPKField() == true) {
- addGetIDOwningClass();
- }
-
- if (_meta.isEmbeddable() && _meta.getIdentityType() == ClassMetaData.ID_APPLICATION) {
- _log.warn(_loc.get("ID-field-in-embeddable-unsupported", _meta.toString()));
- }
-
- addNewObjectIdInstanceMethod(true);
- addNewObjectIdInstanceMethod(false);
- }
- else if (_meta.hasPKFieldsFromAbstractClass()){
- addGetIDOwningClass();
- }
- }
-
- /**
- * Add a method to clear all persistent fields; we'll call this from
- * the new instance method to ensure that unloaded fields have
- * default values.
- */
- private void addClearFieldsMethod()
- throws NoSuchMethodException {
- // protected void pcClearFields ()
- BCMethod method = _pc.declareMethod(PRE + "ClearFields", void.class,
- null);
- method.makeProtected();
- Code code = method.getCode(true);
-
- // super.pcClearFields ()
- if (_meta.getPCSuperclass() != null && !getCreateSubclass()) {
- code.aload().setThis();
- code.invokespecial().setMethod(getType(_meta.
- getPCSuperclassMetaData()), PRE + "ClearFields", void.class,
- null);
- }
-
- FieldMetaData[] fmds = _meta.getDeclaredFields();
- for (int i = 0; i < fmds.length; i++) {
- if (fmds[i].getManagement() != FieldMetaData.MANAGE_PERSISTENT)
- continue;
-
- loadManagedInstance(code, false);
- switch (fmds[i].getDeclaredTypeCode()) {
- case JavaTypes.BOOLEAN:
- case JavaTypes.BYTE:
- case JavaTypes.CHAR:
- case JavaTypes.INT:
- case JavaTypes.SHORT:
- code.constant().setValue(0);
- break;
- case JavaTypes.DOUBLE:
- code.constant().setValue(0D);
- break;
- case JavaTypes.FLOAT:
- code.constant().setValue(0F);
- break;
- case JavaTypes.LONG:
- code.constant().setValue(0L);
- break;
- default:
- code.constant().setNull();
- break;
- }
-
- addSetManagedValueCode(code, fmds[i]);
- }
-
- code.vreturn();
- code.calculateMaxStack();
- code.calculateMaxLocals();
- }
-
- /**
- * Adds the <code>pcNewInstance</code> method to the bytecode.
- * These methods are used by the impl helper to create new
- * managed instances efficiently without reflection.
- *
- * @param oid set to true to mimic the method version that takes
- * an oid value as well as a state manager
- */
- private void addNewInstanceMethod(boolean oid) {
- // public PersistenceCapable pcNewInstance (...)
- Class[] args =
- (oid) ? new Class[]{ SMTYPE, Object.class, boolean.class }
- : new Class[]{ SMTYPE, boolean.class };
- BCMethod method = _pc.declareMethod(PRE + "NewInstance", PCTYPE, args);
- Code code = method.getCode(true);
-
- // if the type is abstract, throw a UserException
- if (_pc.isAbstract()) {
- throwException(code, USEREXCEP);
-
- code.calculateMaxStack();
- code.calculateMaxLocals();
- return;
- }
-
- // XXX pc = new XXX ();
- code.anew().setType(_pc);
- code.dup();
- code.invokespecial().setMethod("<init>", void.class, null);
- int inst = code.getNextLocalsIndex();
- code.astore().setLocal(inst);
-
- // if (clear)
- // pc.pcClearFields ();
- code.iload().setParam((oid) ? 2 : 1);
- JumpInstruction noclear = code.ifeq();
- code.aload().setLocal(inst);
- code.invokevirtual().setMethod(PRE + "ClearFields", void.class, null);
-
- // pc.pcStateManager = sm;
- noclear.setTarget(code.aload().setLocal(inst));
- code.aload().setParam(0);
- code.putfield().setField(SM, SMTYPE);
-
- // copy key fields from oid
- if (oid) {
- code.aload().setLocal(inst);
- code.aload().setParam(1);
- code.invokevirtual().setMethod(PRE + "CopyKeyFieldsFromObjectId",
- void.class, new Class[]{ Object.class });
- }
-
- // return pc;
- code.aload().setLocal(inst);
- code.areturn();
-
- code.calculateMaxStack();
- code.calculateMaxLocals();
- }
-
- /**
- * Adds the <code>protected static int pcGetManagedFieldCount ()</code>
- * method to the bytecode, returning the inherited field count added
- * to the number of managed fields in the current PersistenceCapable class.
- */
- private void addManagedFieldCountMethod() {
- // protected static int pcGetManagedFieldCount ()
- BCMethod method = _pc.declareMethod(PRE + "GetManagedFieldCount",
- int.class, null);
- method.setStatic(true);
- method.makeProtected();
- Code code = method.getCode(true);
-
- // return <fields> + pcInheritedFieldCount
- // awhite: the above should work, but I'm seeing a messed up situation
- // all of a sudden where when a subclass calls this method, it somehow
- // happens before <clinit> is ever invoked, and so our
- // pcInheritedFieldCount field isn't initialized! so instead,
- // return <fields> + <superclass>.pcGetManagedFieldCount ()
- code.constant().setValue(_meta.getDeclaredFields().length);
- if (_meta.getPCSuperclass() != null) {
- Class superClass = getType(_meta.getPCSuperclassMetaData());
- String superName = getCreateSubclass() ?
- PCEnhancer.toPCSubclassName(superClass) :
- superClass.getName();
- code.invokestatic().setMethod(superName,
- PRE + "GetManagedFieldCount", int.class.getName(), null);
- code.iadd();
- }
- code.ireturn();
- code.calculateMaxStack();
- }
-
- /**
- * Adds the {@link PersistenceCapable#pcProvideField} and
- * {@link PersistenceCapable#pcProvideFields} methods to the bytecode.
- */
- private void addProvideFieldsMethods()
- throws NoSuchMethodException {
- // public void pcProvideField (int fieldNumber)
- BCMethod method = _pc.declareMethod(PRE + "ProvideField", void.class,
- new Class[]{ int.class });
- Code code = method.getCode(true);
-
- // adds everything through the switch ()
- int relLocal = beginSwitchMethod(PRE + "ProvideField", code);
-
- // if no fields in this inst, just throw exception
- FieldMetaData[] fmds = getCreateSubclass() ? _meta.getFields()
- : _meta.getDeclaredFields();
- if (fmds.length == 0)
- throwException(code, IllegalArgumentException.class);
- else {
- // switch (val)
- code.iload().setLocal(relLocal);
- TableSwitchInstruction tabins = code.tableswitch();
- tabins.setLow(0);
- tabins.setHigh(fmds.length - 1);
-
- // <field> = pcStateManager.provided<type>Field
- // (this, fieldNumber);
- for (int i = 0; i < fmds.length; i++) {
- tabins.addTarget(loadManagedInstance(code, false));
- code.getfield().setField(SM, SMTYPE);
- loadManagedInstance(code, false);
- code.iload().setParam(0);
- loadManagedInstance(code, false);
- addGetManagedValueCode(code, fmds[i]);
- code.invokeinterface().setMethod(getStateManagerMethod
- (fmds[i].getDeclaredType(), "provided", false, false));
- code.vreturn();
- }
-
- // default: throw new IllegalArgumentException ()
- tabins.setDefaultTarget(throwException
- (code, IllegalArgumentException.class));
- }
-
- code.calculateMaxStack();
- code.calculateMaxLocals();
-
- addMultipleFieldsMethodVersion(method);
- }
-
- /**
- * Adds the {@link PersistenceCapable#pcReplaceField} and
- * {@link PersistenceCapable#pcReplaceFields} methods to the bytecode.
- */
- private void addReplaceFieldsMethods()
- throws NoSuchMethodException {
- // public void pcReplaceField (int fieldNumber)
- BCMethod method = _pc.declareMethod(PRE + "ReplaceField", void.class,
- new Class[]{ int.class });
- Code code = method.getCode(true);
-
- // adds everything through the switch ()
- int relLocal = beginSwitchMethod(PRE + "ReplaceField", code);
-
- // if no fields in this inst, just throw exception
- FieldMetaData[] fmds = getCreateSubclass() ? _meta.getFields()
- : _meta.getDeclaredFields();
- if (fmds.length == 0)
- throwException(code, IllegalArgumentException.class);
- else {
- // switch (val)
- code.iload().setLocal(relLocal);
- TableSwitchInstruction tabins = code.tableswitch();
- tabins.setLow(0);
- tabins.setHigh(fmds.length - 1);
-
- // <field> = pcStateManager.replace<type>Field
- // (this, fieldNumber);
- for (int i = 0; i < fmds.length; i++) {
- // for the addSetManagedValueCode call below.
- tabins.addTarget(loadManagedInstance(code, false, fmds[i]));
-
- loadManagedInstance(code, false, fmds[i]);
- code.getfield().setField(SM, SMTYPE);
- loadManagedInstance(code, false, fmds[i]);
- code.iload().setParam(0);
- code.invokeinterface().setMethod(getStateManagerMethod
- (fmds[i].getDeclaredType(), "replace", true, false));
- if (!fmds[i].getDeclaredType().isPrimitive())
- code.checkcast().setType(fmds[i].getDeclaredType());
-
- addSetManagedValueCode(code, fmds[i]);
- if(_addVersionInitFlag){
- if(fmds[i].isVersion()){
- // If this case is setting the version field
- // pcVersionInit = true;
- loadManagedInstance(code, false);
- code.constant().setValue(1);
- putfield(code, null, VERSION_INIT_STR, boolean.class);
- }
- }
- code.vreturn();
- }
-
- // default: throw new IllegalArgumentException ()
- tabins.setDefaultTarget(throwException
- (code, IllegalArgumentException.class));
- }
-
- code.calculateMaxStack();
- code.calculateMaxLocals();
-
- addMultipleFieldsMethodVersion(method);
- }
-
- /**
- * Adds the {@link PersistenceCapable#pcCopyFields} method to the bytecode.
- */
- private void addCopyFieldsMethod()
- throws NoSuchMethodException {
- // public void pcCopyField (Object pc, int field)
- BCMethod method = _pc.declareMethod(PRE + "CopyField",
- void.class.getName(),
- new String[]{ _managedType.getName(), int.class.getName() });
- method.makeProtected();
- Code code = method.getCode(true);
-
- // adds everything through the switch ()
- int relLocal = beginSwitchMethod(PRE + "CopyField", code);
-
- // if no fields in this inst, just throw exception
- FieldMetaData[] fmds = getCreateSubclass() ? _meta.getFields()
- : _meta.getDeclaredFields();
- if (fmds.length == 0)
- throwException(code, IllegalArgumentException.class);
- else {
- // switch (val)
- code.iload().setLocal(relLocal);
- TableSwitchInstruction tabins = code.tableswitch();
- tabins.setLow(0);
- tabins.setHigh(fmds.length - 1);
-
- for (int i = 0; i < fmds.length; i++) {
- // <field> = other.<field>;
- // or set<field> (other.get<field>);
- tabins.addTarget(loadManagedInstance(code, false, fmds[i]));
- code.aload().setParam(0);
- addGetManagedValueCode(code, fmds[i], false);
- addSetManagedValueCode(code, fmds[i]);
-
- // break;
- code.vreturn();
- }
-
- // default: throw new IllegalArgumentException ()
- tabins.setDefaultTarget(throwException
- (code, IllegalArgumentException.class));
- }
-
- code.calculateMaxStack();
- code.calculateMaxLocals();
-
- addMultipleFieldsMethodVersion(method);
- }
-
- /**
- * Helper method to add the code common to the beginning of both the
- * pcReplaceField method and the pcProvideField method. This includes
- * calculating the relative field number of the desired field and calling
- * the superclass if necessary.
- *
- * @return the index in which the local variable holding the relative
- * field number is stored
- */
- private int beginSwitchMethod(String name, Code code) {
- boolean copy = (PRE + "CopyField").equals(name);
- int fieldNumber = (copy) ? 1 : 0;
-
- int relLocal = code.getNextLocalsIndex();
- if (getCreateSubclass()) {
- code.iload().setParam(fieldNumber);
- code.istore().setLocal(relLocal);
- return relLocal;
- }
-
- // int rel = fieldNumber - pcInheritedFieldCount
- code.iload().setParam(fieldNumber);
- code.getstatic().setField(INHERIT, int.class);
- code.isub();
- code.istore().setLocal(relLocal);
- code.iload().setLocal(relLocal);
-
- // super: if (rel < 0) super.pcReplaceField (fieldNumber); return;
- // no super: if (rel < 0) throw new IllegalArgumentException ();
- JumpInstruction ifins = code.ifge();
- if (_meta.getPCSuperclass() != null) {
- loadManagedInstance(code, false);
- String[] args;
- if (copy) {
- args = new String[]{ getType(_meta.getPCSuperclassMetaData()).
- getName(), int.class.getName() };
- code.aload().setParam(0);
- } else
- args = new String[]{ int.class.getName() };
- code.iload().setParam(fieldNumber);
- code.invokespecial().setMethod(getType(_meta.
- getPCSuperclassMetaData()).getName(), name,
- void.class.getName(), args);
- code.vreturn();
- } else
- throwException(code, IllegalArgumentException.class);
-
- ifins.setTarget(code.nop());
- return relLocal;
- }
-
- /**
- * This helper method, given the pcReplaceField or pcProvideField
- * method, adds the bytecode for the corresponding 'plural' version
- * of the method -- the version that takes an int[] of fields to
- * to access rather than a single field. The multiple fields version
- * simply loops through the provided indexes and delegates to the
- * singular version for each one.
- */
- private void addMultipleFieldsMethodVersion(BCMethod single) {
- boolean copy = (PRE + "CopyField").equals(single.getName());
-
- // public void <method>s (int[] fields)
- Class[] args = (copy) ? new Class[]{ Object.class, int[].class }
- : new Class[]{ int[].class };
- BCMethod method = _pc.declareMethod(single.getName() + "s",
- void.class, args);
- Code code = method.getCode(true);
-
- int fieldNumbers = 0;
- int inst = 0;
- if (copy) {
- fieldNumbers = 1;
-
- if (getCreateSubclass()) {
- // get the managed instance into the local variable table
- code.aload().setParam(0);
- code.invokestatic().setMethod(ImplHelper.class,
- "getManagedInstance", Object.class,
- new Class[] { Object.class });
- code.checkcast().setType(_managedType);
- inst = code.getNextLocalsIndex();
- code.astore().setLocal(inst);
-
- // there might be a difference between the classes of 'this'
- // vs 'other' in this context; use the PC methods to get the SM
- code.aload().setParam(0);
- code.aload().setThis();
- code.getfield().setField(SM, SMTYPE);
- code.invokestatic().setMethod(ImplHelper.class,
- "toPersistenceCapable", PersistenceCapable.class,
- new Class[] { Object.class, Object.class });
- code.invokeinterface().setMethod(PersistenceCapable.class,
- "pcGetStateManager", StateManager.class, null);
- } else {
- // XXX other = (XXX) pc;
- code.aload().setParam(0);
- code.checkcast().setType(_pc);
- inst = code.getNextLocalsIndex();
- code.astore().setLocal(inst);
-
- // access the other's sm field directly
- code.aload().setLocal(inst);
- code.getfield().setField(SM, SMTYPE);
- }
-
- // if (other.pcStateManager != pcStateManager)
- // throw new IllegalArgumentException
-
- loadManagedInstance(code, false);
- code.getfield().setField(SM, SMTYPE);
- JumpInstruction ifins = code.ifacmpeq();
- throwException(code, IllegalArgumentException.class);
- ifins.setTarget(code.nop());
-
- // if (pcStateManager == null)
- // throw new IllegalStateException
- loadManagedInstance(code, false);
- code.getfield().setField(SM, SMTYPE);
- ifins = code.ifnonnull();
- throwException(code, IllegalStateException.class);
- ifins.setTarget(code.nop());
- }
-
- // for (int i = 0;
- code.constant().setValue(0);
- int idx = code.getNextLocalsIndex();
- code.istore().setLocal(idx);
- JumpInstruction testins = code.go2();
-
- // <method> (fields[i]);
- Instruction bodyins = loadManagedInstance(code, false);
- if (copy)
- code.aload().setLocal(inst);
- code.aload().setParam(fieldNumbers);
- code.iload().setLocal(idx);
- code.iaload();
- code.invokevirtual().setMethod(single);
-
- // i++;
- code.iinc().setIncrement(1).setLocal(idx);
-
- // i < fields.length
- testins.setTarget(code.iload().setLocal(idx));
- code.aload().setParam(fieldNumbers);
- code.arraylength();
- code.ificmplt().setTarget(bodyins);
- code.vreturn();
-
- code.calculateMaxStack();
- code.calculateMaxLocals();
- }
-
- /**
- * Adds the 'stock' methods to the bytecode; these include methods
- * like {@link PersistenceCapable#pcFetchObjectId}
- * and {@link PersistenceCapable#pcIsTransactional}.
- */
- private void addStockMethods()
- throws NoSuchMethodException {
- try {
- // pcGetGenericContext
- translateFromStateManagerMethod(
- AccessController.doPrivileged(
- J2DoPrivHelper.getDeclaredMethodAction(
- SMTYPE, "get" + CONTEXTNAME, (Class[]) null)), false);
-
- // pcFetchObjectId
- translateFromStateManagerMethod(
- AccessController.doPrivileged(
- J2DoPrivHelper.getDeclaredMethodAction(
- SMTYPE, "fetchObjectId", (Class[]) null)), false);
-
- // pcIsDeleted
- translateFromStateManagerMethod(
- AccessController.doPrivileged(
- J2DoPrivHelper.getDeclaredMethodAction(
- SMTYPE, "isDeleted", (Class[]) null)), false);
-
- // pcIsDirty
- translateFromStateManagerMethod(
- AccessController.doPrivileged(
- J2DoPrivHelper.getDeclaredMethodAction(
- SMTYPE, "isDirty", (Class[]) null)), true);
-
- // pcIsNew
- translateFromStateManagerMethod(
- AccessController.doPrivileged(
- J2DoPrivHelper.getDeclaredMethodAction(
- SMTYPE, "isNew", (Class[]) null)), false);
-
- // pcIsPersistent
- translateFromStateManagerMethod(
- AccessController.doPrivileged(
- J2DoPrivHelper.getDeclaredMethodAction(
- SMTYPE, "isPersistent", (Class[]) null)), false);
-
- // pcIsTransactional
- translateFromStateManagerMethod(
- AccessController.doPrivileged(
- J2DoPrivHelper.getDeclaredMethodAction(
- SMTYPE, "isTransactional", (Class[]) null)), false);
-
- // pcSerializing
- translateFromStateManagerMethod(
- AccessController.doPrivileged(
- J2DoPrivHelper.getDeclaredMethodAction(
- SMTYPE, "serializing", (Class[]) null)), false);
-
- // pcDirty
- translateFromStateManagerMethod(
- AccessController.doPrivileged(
- J2DoPrivHelper.getDeclaredMethodAction(
- SMTYPE, "dirty", new Class[]{ String.class })), false);
-
- // pcGetStateManager
- BCMethod meth = _pc.declareMethod(PRE + "GetStateManager",
- StateManager.class, null);
- Code code = meth.getCode(true);
- loadManagedInstance(code, false);
- code.getfield().setField(SM, StateManager.class);
- code.areturn();
- code.calculateMaxStack();
- code.calculateMaxLocals();
- } catch (PrivilegedActionException pae) {
- throw (NoSuchMethodException) pae.getException();
- }
- }
-
- /**
- * Helper method to add a stock method to the bytecode. Each
- * stock method simply delegates to a corresponding StateManager method.
- * Given the StateManager method, then, this function translates it into
- * the wrapper method that should be added to the bytecode.
- */
- private void translateFromStateManagerMethod(Method m,
- boolean isDirtyCheckMethod) {
- // form the name of the method by prepending 'pc' to the sm method
- String name = PRE + StringUtil.capitalize(m.getName());
- Class[] params = m.getParameterTypes();
- Class returnType = m.getReturnType();
-
- // add the method to the pc
- BCMethod method = _pc.declareMethod(name, returnType, params);
- Code code = method.getCode(true);
-
- // if (pcStateManager == null) return <default>;
- loadManagedInstance(code, false);
- code.getfield().setField(SM, SMTYPE);
- JumpInstruction ifins = code.ifnonnull();
- if (returnType.equals(boolean.class))
- code.constant().setValue(false);
- else if (!returnType.equals(void.class))
- code.constant().setNull();
- code.xreturn().setType(returnType);
-
- // if this is the dirty-check method and we're subclassing but not
- // redefining, hook into PCHelper to do the dirty check
- if (isDirtyCheckMethod && !getRedefine()) {
- // RedefinitionHelper.dirtyCheck(sm);
- ifins.setTarget(loadManagedInstance(code, false));
- code.getfield().setField(SM, SMTYPE);
- code.dup(); // for the return statement below
- code.invokestatic().setMethod(RedefinitionHelper.class,
- "dirtyCheck", void.class, new Class[] { SMTYPE });
- } else {
- ifins.setTarget(loadManagedInstance(code, false));
- code.getfield().setField(SM, SMTYPE);
- }
-
- // return pcStateManager.<method> (<args>);
- // managed instance loaded above in if-else block
- for (int i = 0; i < params.length; i++)
- code.xload().setParam(i);
- code.invokeinterface().setMethod(m);
- code.xreturn().setType(returnType);
-
- code.calculateMaxStack();
- code.calculateMaxLocals();
- }
-
- /**
- * Adds the {@link PersistenceCapable#pcGetVersion} method to the bytecode.
- */
- private void addGetVersionMethod()
- throws NoSuchMethodException {
- BCMethod method = _pc.declareMethod(PRE + "GetVersion", Object.class,
- null);
- Code code = method.getCode(true);
-
- // if (pcStateManager == null)
- loadManagedInstance(code, false);
- code.getfield().setField(SM, SMTYPE);
- JumpInstruction ifins = code.ifnonnull();
- FieldMetaData versionField = _meta.getVersionField();
-
- if (versionField == null)
- code.constant().setNull(); // return null;
- else {
- // return <versionField>;
- Class wrapper = toPrimitiveWrapper(versionField);
- if (wrapper != versionField.getDeclaredType()) {
- code.anew().setType(wrapper);
- code.dup();
- }
- loadManagedInstance(code, false);
- addGetManagedValueCode(code, versionField);
- if (wrapper != versionField.getDeclaredType())
- code.invokespecial().setMethod(wrapper, "<init>", void.class,
- new Class[]{ versionField.getDeclaredType() });
- }
- code.areturn();
-
- // return pcStateManager.getVersion ();
- ifins.setTarget(loadManagedInstance(code, false));
- code.getfield().setField(SM, SMTYPE);
- code.invokeinterface().setMethod(SMTYPE, "getVersion", Object.class,
- null);
- code.areturn();
-
- code.calculateMaxStack();
- code.calculateMaxLocals();
- }
-
- /**
- * Return the version field type as a primitive wrapper, or null if
- * the version field is not primitive.
- */
- private Class toPrimitiveWrapper(FieldMetaData fmd) {
- switch (fmd.getDeclaredTypeCode()) {
- case JavaTypes.BOOLEAN:
- return Boolean.class;
- case JavaTypes.BYTE:
- return Byte.class;
- case JavaTypes.CHAR:
- return Character.class;
- case JavaTypes.DOUBLE:
- return Double.class;
- case JavaTypes.FLOAT:
- return Float.class;
- case JavaTypes.INT:
- return Integer.class;
- case JavaTypes.LONG:
- return Long.class;
- case JavaTypes.SHORT:
- return Short.class;
- }
- return fmd.getDeclaredType();
- }
-
- /**
- * Adds the {@link PersistenceCapable#pcReplaceStateManager}
- * method to the bytecode.
- */
- private void addReplaceStateManagerMethod() {
- // public void pcReplaceStateManager (StateManager sm)
- BCMethod method = _pc.declareMethod(PRE + "ReplaceStateManager",
- void.class, new Class[]{ SMTYPE });
- method.getExceptions(true).addException(SecurityException.class);
- Code code = method.getCode(true);
-
- // if (pcStateManager != null)
- // pcStateManager = pcStateManager.replaceStateManager(sm);
- loadManagedInstance(code, false);
- code.getfield().setField(SM, SMTYPE);
- JumpInstruction ifins = code.ifnull();
- loadManagedInstance(code, false);
- loadManagedInstance(code, false);
- code.getfield().setField(SM, SMTYPE);
- code.aload().setParam(0);
- code.invokeinterface().setMethod(SMTYPE, "replaceStateManager",
- SMTYPE, new Class[]{ SMTYPE });
- code.putfield().setField(SM, SMTYPE);
- code.vreturn();
-
- // SecurityManager sec = System.getSecurityManager ();
- // if (sec != null)
- // sec.checkPermission (Permission.SET_STATE_MANAGER);
- ifins.setTarget(code.invokestatic().setMethod(System.class,
- "getSecurityManager", SecurityManager.class, null));
-
- // pcStateManager = sm;
- ifins.setTarget(loadManagedInstance(code, false));
- code.aload().setParam(0);
- code.putfield().setField(SM, SMTYPE);
- code.vreturn();
-
- code.calculateMaxStack();
- code.calculateMaxLocals();
- }
-
- /**
- * Creates the PersistenceCapable methods dealing with application
- * identity and gives them no-op implementations.
- */
- private void addNoOpApplicationIdentityMethods() {
- // public void pcCopyKeyFieldsToObjectId (ObjectIdFieldSupplier fs,
- // Object oid)
- BCMethod method = _pc.declareMethod(PRE + "CopyKeyFieldsToObjectId",
- void.class, new Class[]{ OIDFSTYPE, Object.class });
- Code code = method.getCode(true);
- code.vreturn();
- code.calculateMaxLocals();
-
- // public void pcCopyKeyFieldsToObjectId (Object oid)
- method = _pc.declareMethod(PRE + "CopyKeyFieldsToObjectId",
- void.class, new Class[]{ Object.class });
- code = method.getCode(true);
- code.vreturn();
- code.calculateMaxLocals();
-
- // public void pcCopyKeyFieldsFromObjectId (ObjectIdFieldConsumer fc,
- // Object oid)
- method = _pc.declareMethod(PRE + "CopyKeyFieldsFromObjectId",
- void.class, new Class[]{ OIDFCTYPE, Object.class });
- code = method.getCode(true);
- code.vreturn();
- code.calculateMaxLocals();
-
- // public void pcCopyKeyFieldsFromObjectId (Object oid)
- method = _pc.declareMethod(PRE + "CopyKeyFieldsFromObjectId",
- void.class, new Class[]{ Object.class });
- code = method.getCode(true);
- code.vreturn();
- code.calculateMaxLocals();
-
- // public Object pcNewObjectIdInstance ()
- method = _pc.declareMethod(PRE + "NewObjectIdInstance",
- Object.class, null);
- code = method.getCode(true);
- code.constant().setNull();
- code.areturn();
- code.calculateMaxStack();
- code.calculateMaxLocals();
-
- // public Object pcNewObjectIdInstance (Object obj)
- method = _pc.declareMethod(PRE + "NewObjectIdInstance",
- Object.class, new Class[]{ Object.class });
- code = method.getCode(true);
- code.constant().setNull();
- code.areturn();
- code.calculateMaxStack();
- code.calculateMaxLocals();
- }
-
- /**
- * Adds the <code>pcCopyKeyFieldsToObjectId</code> methods
- * to classes using application identity.
- */
- private void addCopyKeyFieldsToObjectIdMethod(boolean fieldManager)
- throws NoSuchMethodException {
- // public void pcCopyKeyFieldsToObjectId (ObjectIdFieldSupplier fs,
- // Object oid)
- String[] args = (fieldManager) ?
- new String[]{ OIDFSTYPE.getName(), Object.class.getName() }
- : new String[]{ Object.class.getName() };
- BCMethod method = _pc.declareMethod(PRE + "CopyKeyFieldsToObjectId",
- void.class.getName(), args);
- Code code = method.getCode(true);
-
- // single field identity always throws exception
- if (_meta.isOpenJPAIdentity()) {
- throwException(code, INTERNEXCEP);
-
- code.calculateMaxStack();
- code.calculateMaxLocals();
- return;
- }
-
- // call superclass method
- if (_meta.getPCSuperclass() != null && !getCreateSubclass()) {
- loadManagedInstance(code, false);
- for (int i = 0; i < args.length; i++)
- code.aload().setParam(i);
- code.invokespecial().setMethod(getType(_meta.
- getPCSuperclassMetaData()).getName(),
- PRE + "CopyKeyFieldsToObjectId", void.class.getName(), args);
- }
-
- // Object id = oid;
- if (fieldManager)
- code.aload().setParam(1);
- else
- code.aload().setParam(0);
-
- if (_meta.isObjectIdTypeShared()) {
- // oid = ((ObjectId) id).getId ();
- code.checkcast().setType(ObjectId.class);
- code.invokevirtual().setMethod(ObjectId.class, "getId",
- Object.class, null);
- }
-
- // <oid type> id = (<oid type>) oid;
- int id = code.getNextLocalsIndex();
- Class oidType = _meta.getObjectIdType();
- code.checkcast().setType(oidType);
- code.astore().setLocal(id);
-
- // int inherited = pcInheritedFieldCount;
- int inherited = 0;
- if (fieldManager) {
- code.getstatic().setField(INHERIT, int.class);
- inherited = code.getNextLocalsIndex();
- code.istore().setLocal(inherited);
- }
-
- // id.<field> = fs.fetch<type>Field (<index>); or...
- // id.<field> = pc.<field>;
- FieldMetaData[] fmds = getCreateSubclass() ? _meta.getFields()
- : _meta.getDeclaredFields();
- Class<?> type;
- String name;
- Field field;
- Method setter;
- boolean reflect;
- // If optimizeIdCopy is enabled and not a field manager method, try to
- // optimize the copyTo by using a public constructor instead of reflection
- if (_optimizeIdCopy) {
- ArrayList<Integer> pkfields = optimizeIdCopy(oidType, fmds);
- if (pkfields != null) {
- // search for a constructor on the IdClass that can be used
- // to construct the IdClass
- int parmOrder[] = getIdClassConstructorParmOrder(oidType, pkfields, fmds);
- if (parmOrder != null) {
- // If using a field manager, values must be loaded into locals so they can be properly ordered
- // as constructor parameters.
- int[] localIndexes = new int[fmds.length];
- if (fieldManager) {
- for (int k = 0; k < fmds.length; k++) {
- if (!fmds[k].isPrimaryKey())
- continue;
- code.aload().setParam(0);
- code.constant().setValue(k);
- code.iload().setLocal(inherited);
- code.iadd();
- code.invokeinterface().setMethod(getFieldSupplierMethod(fmds[k].getObjectIdFieldType()));
- localIndexes[k] = code.getNextLocalsIndex();
- storeLocalValue(code, localIndexes[k], fmds[k].getObjectIdFieldTypeCode());
- }
- }
-
- // found a matching constructor. parm array is constructor parm order
- code.anew().setType(oidType);
- code.dup();
- // build the parm list in order
- Class<?>[] clsArgs = new Class<?>[parmOrder.length];
- for (int i = 0; i < clsArgs.length; i++) {
- int parmIndex = parmOrder[i];
- clsArgs[i] = fmds[parmIndex].getObjectIdFieldType();
- if (!fieldManager) {
- loadManagedInstance(code, false);
- addGetManagedValueCode(code, fmds[parmIndex]);
- } else {
- // Load constructor parameters in appropriate order
- loadLocalValue(code, localIndexes[parmIndex], fmds[parmIndex].getObjectIdFieldTypeCode());
- if (fmds[parmIndex].getObjectIdFieldTypeCode() == JavaTypes.OBJECT &&
- !fmds[parmIndex].getDeclaredType().isEnum()) {
- code.checkcast().setType(ObjectId.class);
- code.invokevirtual().setMethod(ObjectId.class, "getId",
- Object.class, null);
- }
- // if the type of this field meta data is
- // non-primitive and non-string, be sure to cast
- // to the appropriate type.
- if (!clsArgs[i].isPrimitive()
- && !clsArgs[i].getName().equals(String.class.getName()))
- code.checkcast().setType(clsArgs[i]);
- }
- }
- // invoke the public constructor to create a new local id
- code.invokespecial().setMethod(oidType, "<init>", void.class, clsArgs);
- int ret = code.getNextLocalsIndex();
- code.astore().setLocal(ret);
-
- // swap out the app id with the new one
- code.aload().setLocal( fieldManager ? 2 : 1);
- code.checkcast().setType(ObjectId.class);
- code.aload().setLocal(ret);
- code.invokestatic().setMethod(ApplicationIds.class,
- "setAppId", void.class, new Class[] { ObjectId.class,
- Object.class });
- code.vreturn();
-
- code.calculateMaxStack();
- code.calculateMaxLocals();
- return;
- }
- }
- }
-
- for (int i = 0; i < fmds.length; i++) {
- if (!fmds[i].isPrimaryKey())
- continue;
- code.aload().setLocal(id);
-
- name = fmds[i].getName();
- type = fmds[i].getObjectIdFieldType();
- if (isFieldAccess(fmds[i])) {
- setter = null;
- field = Reflection.findField(oidType, name, true);
- reflect = !Modifier.isPublic(field.getModifiers());
- if (reflect) {
- code.classconstant().setClass(oidType);
- code.constant().setValue(name);
- code.constant().setValue(true);
- code.invokestatic().setMethod(Reflection.class,
- "findField", Field.class, new Class[] { Class.class,
- String.class, boolean.class });
- }
- } else {
- field = null;
- setter = Reflection.findSetter(oidType, name, type, true);
- reflect = !Modifier.isPublic(setter.getModifiers());
- if (reflect) {
- code.classconstant().setClass(oidType);
- code.constant().setValue(name);
- code.classconstant().setClass(type);
- code.constant().setValue(true);
- code.invokestatic().setMethod(Reflection.class,
- "findSetter", Method.class, new Class[] { Class.class,
- String.class, Class.class, boolean.class });
- }
- }
-
- if (fieldManager) {
- code.aload().setParam(0);
- code.constant().setValue(i);
- code.iload().setLocal(inherited);
- code.iadd();
- code.invokeinterface().setMethod
- (getFieldSupplierMethod(type));
- if (fmds[i].getObjectIdFieldTypeCode() == JavaTypes.OBJECT &&
- !fmds[i].getDeclaredType().isEnum()) {
- code.checkcast().setType(ObjectId.class);
- code.invokevirtual().setMethod(ObjectId.class, "getId",
- Object.class, null);
- }
-
- // if the type of this field meta data is
- // non-primitive and non-string, be sure to cast
- // to the appropriate type.
- if (!reflect && !type.isPrimitive()
- && !type.getName().equals(String.class.getName()))
- code.checkcast().setType(type);
- } else {
- loadManagedInstance(code, false);
- addGetManagedValueCode(code, fmds[i]);
-
- // get id/pk from pc instance
- if (fmds[i].getDeclaredTypeCode() == JavaTypes.PC)
- addExtractObjectIdFieldValueCode(code, fmds[i]);
- }
-
- if (reflect && field != null) {
- code.invokestatic().setMethod(Reflection.class, "set",
- void.class, new Class[] { Object.class, Field.class,
- (type.isPrimitive()) ? type : Object.class });
- } else if (reflect) {
- code.invokestatic().setMethod(Reflection.class, "set",
- void.class, new Class[] { Object.class, Method.class,
- (type.isPrimitive()) ? type : Object.class });
- } else if (field != null)
- code.putfield().setField(field);
- else
- code.invokevirtual().setMethod(setter);
- }
- code.vreturn();
-
- code.calculateMaxStack();
- code.calculateMaxLocals();
- }
-
- /**
- * Adds the appropriate load method for the given type and local
- * index.
- */
- private void loadLocalValue(Code code, int locidx, int typeCode) {
- switch (typeCode) {
- case JavaTypes.CHAR:
- case JavaTypes.BYTE:
- case JavaTypes.SHORT:
- case JavaTypes.INT:
- code.iload().setLocal(locidx);
- break;
- case JavaTypes.DOUBLE:
- code.dload().setLocal(locidx);
- break;
- case JavaTypes.FLOAT:
- code.fload().setLocal(locidx);
- break;
- case JavaTypes.LONG:
- code.lload().setLocal(locidx);
- break;
- default:
- code.aload().setLocal(locidx);
- break;
- }
- }
-
- /**
- * Adds the appropriate store method for the given type and local
- * index.
- */
[... 2923 lines stripped ...]