diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractMetaDataDefaults.java b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractMetaDataDefaults.java
index 055f786f6..7c70e2391 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractMetaDataDefaults.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractMetaDataDefaults.java
@@ -179,7 +179,8 @@ public abstract class AbstractMetaDataDefaults
FieldMetaData fmd;
for (int i = 0; i < fieldNames.length; i ++) {
String property = fieldNames[i];
- member = getMemberByProperty(meta, property);
+ member = getMemberByProperty(meta, property,
+ AccessCode.UNKNOWN, true);
if (member == null) // transient or indeterminable access
continue;
fmd = meta.addDeclaredField(property, fieldTypes[i]);
@@ -240,13 +241,6 @@ public abstract class AbstractMetaDataDefaults
}
- /**
- * Called when populating from PCRegistry when only property names are
- * available.
- */
- protected abstract Member getMemberByProperty(ClassMetaData meta,
- String property);
-
/**
* Return the list of fields in meta that use field access,
* or null if a list of fields is unobtainable. An empty list
@@ -333,34 +327,10 @@ public abstract class AbstractMetaDataDefaults
return null;
if (fmd.getBackingMember() != null)
return fmd.getBackingMember();
- return getMemberByProperty(fmd.getDeclaringMetaData(), fmd.getName());
-// try {
-// //### note that we might not have access to declaring metadata yet
-// //### (this could be used during parse), so we have to settle for
-// //### defining. could cause problems if maps a superclass field
-// //### where the superclass uses a different access type
-// if (fmd.getBackingMember() == null) {
-// if ((fmd.getDefiningMetaData().getAccessType() &
-// ClassMetaData.ACCESS_FIELD) == ClassMetaData.ACCESS_FIELD)
-// return AccessController.doPrivileged(
-// J2DoPrivHelper.getDeclaredFieldAction(
-// fmd.getDeclaringType(), fmd.getName()));
-// return Reflection.findGetter(fmd.getDeclaringType(),
-// fmd.getName(), true);
-// } else {
-// return fmd.getBackingMember();
-// }
-// } catch (OpenJPAException ke) {
-// throw ke;
-// } catch (Exception e) {
-// if (e instanceof PrivilegedActionException)
-// e = ((PrivilegedActionException) e).getException();
-// throw new InternalException(e);
-// }
+ return getMemberByProperty(fmd.getDeclaringMetaData(), fmd.getName(),
+ fmd.getAccessType(), true);
}
-
-
public Class> getUnimplementedExceptionType() {
return UnsupportedOperationException.class;
}
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AccessCode.java b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AccessCode.java
index 2a1484298..2f1f8ceb0 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AccessCode.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AccessCode.java
@@ -18,6 +18,9 @@
*/
package org.apache.openjpa.meta;
+import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.util.UserException;
+
/**
* Represents access styles for members of a class and field through a
* 5-bit integer.
@@ -74,6 +77,8 @@ public class AccessCode {
public static int EXPLICIT = 2 << 2;
public static int MIXED = 2 << 3;
+ private static Localizer _loc = Localizer.forPackage(AccessCode.class);
+
/**
* Affirms if the given code is valid.
*/
@@ -167,6 +172,17 @@ public class AccessCode {
return false;
}
+ public static int mergeFieldCode(ClassMetaData meta, FieldMetaData fmd,
+ int fCode) {
+ int cCode = meta.getAccessType();
+ try {
+ return mergeFieldCode(cCode, fCode);
+ } catch (IllegalStateException e) {
+ throw new UserException(_loc.get("access-illegal-merge",
+ fmd.getFullName(false), toString(fCode), toString(cCode)));
+ }
+ }
+
/**
* Merges the field access type with the class access type provided such
* merge is valid.
@@ -192,8 +208,8 @@ public class AccessCode {
if (fCode == cCode)
return cCode;
else
- throw new IllegalStateException(toString(cCode) +
- " not compatible to " + toString(fCode));
+ throw new IllegalStateException("Can not merge field " +
+ toString(fCode) + " to class " + toString(cCode));
}
}
return cCode;
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java
index b05bf55f8..38ed3bb57 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java
@@ -697,7 +697,7 @@ public class ClassMetaData
* it may have the side-effect of changing the access code of this receiver.
*/
void mergeFieldAccess(FieldMetaData fmd, int fCode) {
- setAccessType(AccessCode.mergeFieldCode(_accessType, fCode));
+ setAccessType(AccessCode.mergeFieldCode(this, fmd, fCode));
}
/**
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataDefaults.java b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataDefaults.java
index a3aec0a42..60ae7c7e7 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataDefaults.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataDefaults.java
@@ -83,6 +83,22 @@ public interface MetaDataDefaults
* Return the backing member for the given field metadata.
*/
public Member getBackingMember(FieldMetaData field);
+
+ /**
+ * Get the field or getter for the given attribute of the given class.
+ *
+ * @param meta is the declaring class
+ * @param attribute name of the logical attribute
+ * @param access whether to look for the field of getter method.
+ * If unknown, then field or property is chosen based on the access type
+ * used by the given class.
+ * @param scanAnnotation if true and access is unknown then scans the
+ * annotation on the member to determine access.
+ *
+ * @since 2.0.0
+ */
+ public Member getMemberByProperty(ClassMetaData meta, String attribute,
+ int access, boolean scanAnnotation);
/**
* Return a runtime exception class to throw for un-implemented
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/NoneMetaDataFactory.java b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/NoneMetaDataFactory.java
index e390c4c57..4e3cd02d4 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/NoneMetaDataFactory.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/NoneMetaDataFactory.java
@@ -131,7 +131,12 @@ public class NoneMetaDataFactory
return null;
}
- public Class getUnimplementedExceptionType() {
+ public Member getMemberByProperty(ClassMetaData meta, String property,
+ int access, boolean scan) {
+ return null;
+ }
+
+ public Class extends Exception> getUnimplementedExceptionType() {
return null;
}
diff --git a/openjpa-kernel/src/main/resources/org/apache/openjpa/meta/localizer.properties b/openjpa-kernel/src/main/resources/org/apache/openjpa/meta/localizer.properties
index 1b9931e82..a366a8e12 100644
--- a/openjpa-kernel/src/main/resources/org/apache/openjpa/meta/localizer.properties
+++ b/openjpa-kernel/src/main/resources/org/apache/openjpa/meta/localizer.properties
@@ -23,7 +23,8 @@ access-inconsistent-inherit: "{1}" for class "{0}" is not consistent with \
"{3}" used by its persistent superclass "{2}". All persistent classes in \
an inheritance hierarchy must use a single implicit field or property \
based access style or explicitly declare an access style.
-
+access-illegal-merge: Field "{0}" with "{1}" is not compatible with "{2}" \
+ used by its declaring class.
meta-reflect: Using reflection for metadata generation.
gen-meta: Generating default metadata for type "{0}".
load-cls: Loading metadata for "{0}" under mode "{1}".
diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java
index 8f7ab5284..1b1ea49c6 100644
--- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java
+++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java
@@ -314,7 +314,7 @@ public class PersistenceMetaDataDefaults
if (sup != null && !AccessCode.isUnknown(sup))
return sup.getAccessType();
- return AccessCode.FIELD;
+ return getDefaultAccessType();
}
/**
@@ -598,33 +598,34 @@ public class PersistenceMetaDataDefaults
/**
* Gets either the instance field or the getter method depending upon the
* access style of the given meta-data.
- *
- * Defining class is used instead of declaring class because this method
- * may be invoked during parsing phase when declaring meta-data may not be
- * available.
*/
- @Override
- protected Member getMemberByProperty(ClassMetaData meta, String property) {
+ public Member getMemberByProperty(ClassMetaData meta, String property,
+ int access, boolean applyDefaultRule) {
Class> cls = meta.getDescribedType();
Field field = Reflection.findField(cls, property, false);;
Method getter = Reflection.findGetter(cls, property, false);
+ Method setter = Reflection.findSetter(cls, property, false);
+ int accessCode = AccessCode.isUnknown(access) ? meta.getAccessType() :
+ access;
+ if (field == null && getter == null)
+ error(meta, _loc.get("access-no-property", cls, property));
if (isAnnotated(field) && isAnnotated(getter))
throw new IllegalStateException(_loc.get("access-duplicate",
field, getter).toString());
- if (AccessCode.isField(meta)) {
+ if (AccessCode.isField(accessCode)) {
if (isAnnotatedAccess(getter, AccessType.PROPERTY)) {
meta.setAccessType(AccessCode.MIXED | meta.getAccessType());
return getter;
}
- return field;
- } else if (AccessCode.isProperty(meta)) {
+ return field == null ? getter : field;
+ } else if (AccessCode.isProperty(accessCode)) {
if (isAnnotatedAccess(field, AccessType.FIELD)) {
meta.setAccessType(AccessCode.MIXED | meta.getAccessType());
return field;
}
- return getter;
- } else if (AccessCode.isUnknown(meta)) {
+ return getter == null ? field : getter;
+ } else if (AccessCode.isUnknown(accessCode)) {
if (isAnnotated(field)) {
meta.setAccessType(AccessCode.FIELD);
return field;
diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java
index 0e10a6411..d590f79cd 100644
--- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java
+++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java
@@ -24,8 +24,6 @@ import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.net.URL;
-import java.security.AccessController;
-import java.security.PrivilegedActionException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
@@ -35,7 +33,6 @@ import java.util.Set;
import java.util.Stack;
import javax.persistence.CascadeType;
import javax.persistence.GenerationType;
-import javax.persistence.LockModeType;
import static javax.persistence.CascadeType.*;
@@ -54,8 +51,8 @@ import org.apache.openjpa.kernel.jpql.JPQLParser;
import org.apache.openjpa.lib.conf.Configurations;
import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.lib.meta.CFMetaDataParser;
+import org.apache.openjpa.lib.meta.SourceTracker;
import org.apache.openjpa.lib.meta.XMLVersionParser;
-import org.apache.openjpa.lib.util.J2DoPrivHelper;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.meta.AccessCode;
import org.apache.openjpa.meta.ClassMetaData;
@@ -78,10 +75,13 @@ import org.apache.openjpa.util.ImplHelper;
import serp.util.Numbers;
/**
- * Custom SAX parser used by the system to quickly parse persistence i
- * metadata files.
+ * Custom SAX parser used by the system to quickly parse persistence
+ * metadata files. This parser may invoke
+ * {@linkplain AnnotationPersistenceMetaDataParser another parser} to scan
+ * source code annotation.
*
* @author Steve Kim
+ * @author Pinaki Poddar
* @nojavadoc
*/
public class XMLPersistenceMetaDataParser
@@ -108,9 +108,9 @@ public class XMLPersistenceMetaDataParser
new HashMap();
// Map for storing deferred metadata which needs to be populated
- // after embeddedables are loaded.
- private static final Map> _embeddables =
- new HashMap>();
+ // after embeddables are loaded.
+ private static final Map, ArrayList>
+ _embeddables = new HashMap, ArrayList>();
static {
_elems.put(ELEM_PKG, ELEM_PKG);
@@ -178,10 +178,10 @@ public class XMLPersistenceMetaDataParser
private int _mode = MODE_NONE;
private boolean _override = false;
- private final Stack _elements = new Stack();
- private final Stack _parents = new Stack();
+ private final Stack