Improve error message when checking metadata access types; correct recursive method to always include superclass information.

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@614606 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Patrick Linskey 2008-01-23 18:15:09 +00:00
parent 3aa60007dd
commit 13dd4f2252
6 changed files with 192 additions and 12 deletions

View File

@ -24,6 +24,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.util.List;
import org.apache.openjpa.enhance.PCRegistry;
import org.apache.openjpa.enhance.Reflection;
@ -153,9 +154,17 @@ public abstract class AbstractMetaDataDefaults
// the same time
access = getAccessType(meta);
if ((access & ClassMetaData.ACCESS_FIELD) != 0
&& (access & ClassMetaData.ACCESS_PROPERTY) != 0)
throw new UserException(_loc.get("access-field-and-prop",
meta.getDescribedType().getName()));
&& (access & ClassMetaData.ACCESS_PROPERTY) != 0) {
List fields = getFieldAccessNames(meta);
List props = getPropertyAccessNames(meta);
if (fields != null || props != null)
throw new UserException(_loc.get(
"access-field-and-prop-hints",
meta.getDescribedType().getName(), fields, props));
else
throw new UserException(_loc.get("access-field-and-prop",
meta.getDescribedType().getName()));
}
}
meta.setAccessType(access);
@ -263,6 +272,34 @@ public abstract class AbstractMetaDataDefaults
return ClassMetaData.ACCESS_FIELD;
}
/**
* Return the list of fields in <code>meta</code> that use field access,
* or <code>null</code> if a list of fields is unobtainable. An empty list
* should be returned if the list of fields is obtainable, but there
* happens to be no field access in <code>meta</code>.
*
* This is used for error reporting purposes only, so need not be efficient.
*
* This implementation returns <code>null</code>.
*/
protected List getFieldAccessNames(ClassMetaData meta) {
return null;
}
/**
* Return the list of methods in <code>meta</code> that use property access,
* or <code>null</code> if a list of methods is unobtainable. An empty list
* should be returned if the list of methods is obtainable, but there
* happens to be no property access in <code>meta</code>.
*
* This is used for error reporting purposes only, so need not be efficient.
*
* This implementation returns <code>null</code>.
*/
protected List getPropertyAccessNames(ClassMetaData meta) {
return null;
}
/**
* Return the field name for the given member. This will only be invoked
* on members of the right type (field vs. method). Return null if the

View File

@ -267,6 +267,10 @@ lifecycle-resolved: Could add the following callback adapters to "{0}", as \
the lifecycle metadata is already resolved: {1}
access-field-and-prop: Type "{0}" attempts to use both field and property \
access. Only one access method is permitted.
access-field-and-prop-hints: Type "{0}" attempts to use both field and \
property access. Only one access method is permitted. Field access is used \
on the following fields: {1}. Property access is used on the following \
methods: {2}.
unsupported-id-type: Type "{0}" declares field "{1}" as a primary key, but \
keys of type "{2}" are not supported.
empty-fg-name: Attempt to add an unnamed fetch group to "{0}".

View File

@ -0,0 +1,52 @@
/*
* 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
*
* 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.persistence.jdbc.annotations;
import javax.persistence.PersistenceException;
import javax.persistence.EntityManagerFactory;
import org.apache.openjpa.persistence.test.PersistenceTestCase;
public class TestMixedAccess extends PersistenceTestCase {
public void testMixedAccessEntityError() {
try {
EntityManagerFactory emf = createEMF(UnenhancedMixedAccess.class);
emf.createEntityManager().close();
} catch (RuntimeException e) {
String msg = e.getMessage();
if (!(msg.contains("UnenhancedMixedAccess.id") &&
msg.contains("UnenhancedMixedAccess.getStringField")))
throw e;
}
}
public void testInappropriateTransientError() {
try {
EntityManagerFactory emf = createEMF(
UnenhancedInappropriateTransient.class);
emf.createEntityManager().close();
} catch (RuntimeException e) {
String msg = e.getMessage();
if (!(msg.contains("UnenhancedInappropriateTransient.id") &&
msg.contains("UnenhancedInappropriateTransient.prePersist")))
throw e;
}
}
}

View File

@ -0,0 +1,34 @@
/*
* 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
*
* 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.persistence.jdbc.annotations;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Transient;
import javax.persistence.PrePersist;
@Entity
public class UnenhancedInappropriateTransient {
@Id private int id;
@Transient @PrePersist public void prePersist() {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,37 @@
/*
* 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
*
* 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.persistence.jdbc.annotations;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Transient;
@Entity
public class UnenhancedMixedAccess {
@Id private int id;
@Transient public String getStringField() {
throw new UnsupportedOperationException();
}
public void setStringField(String str) {
throw new UnsupportedOperationException();
}
}

View File

@ -30,6 +30,8 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.List;
import java.util.ArrayList;
import javax.persistence.Basic;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
@ -257,22 +259,36 @@ public class PersistenceMetaDataDefaults
return ClassMetaData.ACCESS_UNKNOWN;
int access = 0;
if (usesAccess((Field[]) AccessController.doPrivileged(
J2DoPriv5Helper.getDeclaredFieldsAction(cls))))
if (annotated((Field[]) AccessController.doPrivileged(
J2DoPriv5Helper.getDeclaredFieldsAction(cls))).size() > 0)
access |= ClassMetaData.ACCESS_FIELD;
if (usesAccess((Method[]) AccessController.doPrivileged(
J2DoPriv5Helper.getDeclaredMethodsAction(cls)))
if (annotated((Method[]) AccessController.doPrivileged(
J2DoPriv5Helper.getDeclaredMethodsAction(cls))).size() > 0
|| cls.isInterface()) // OpenJPA managed ifaces must use prop access
access |= ClassMetaData.ACCESS_PROPERTY;
return (access == 0) ? getAccessType(cls.getSuperclass()) : access;
return getAccessType(cls.getSuperclass()) | access;
}
@Override
protected List getFieldAccessNames(ClassMetaData meta) {
return annotated((Field[]) AccessController.doPrivileged(
J2DoPriv5Helper.getDeclaredFieldsAction(meta.getDescribedType())));
}
@Override
protected List getPropertyAccessNames(ClassMetaData meta) {
return annotated((Method[]) AccessController.doPrivileged(
J2DoPriv5Helper.getDeclaredMethodsAction(meta.getDescribedType())));
}
/**
* Return whether the given members have persistence annotations.
* Return the members of <code>members</code> that have persistence
* annotations.
*/
private static boolean usesAccess(AnnotatedElement[] members) {
private static List annotated(AnnotatedElement[] members) {
Annotation[] annos;
String name;
List annotated = new ArrayList(members.length);
for (int i = 0; i < members.length; i++) {
annos = (Annotation[]) AccessController.doPrivileged(J2DoPriv5Helper
.getAnnotationsAction(members[i]));
@ -281,10 +297,10 @@ public class PersistenceMetaDataDefaults
if ((name.startsWith("javax.persistence.")
|| name.startsWith("org.apache.openjpa.persistence."))
&& !_ignoredAnnos.contains(name))
return true;
annotated.add(members[i]);
}
}
return false;
return annotated;
}
protected boolean isDefaultPersistent(ClassMetaData meta, Member member,