我使用的是Hibernate 3.6,JPA 2.0和Spring 3.0.6。我的对象中有字段如下:
class PersonContact {
Long eAddressCpId;
ElectronicAddress eAddress;
}
我使用字段访问(在我的orm文件中)和查询/插入/等工作没有问题。这些字段既在类中,也在orm文件中。但是在应用程序启动时,JPA配置加载会发出警告:
2011-02-22 15:38:10,785 [[STANDBY] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'] WARN org.hibernate.cfg.annotations.reflection.JPAOverridenAnnotationReader - Property com.foo.model.contactpoint.ElectronicAddress.eAddress not found in class but described in (possible typo error) 2011-02-22 15:38:10,801 [[STANDBY] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'] WARN org.hibernate.cfg.annotations.reflection.JPAOverridenAnnotationReader - Property com.foo.model.person.PersonContact.eAddressCpId not found in class but described in (possible typo error) 2011-02-22 15:38:10,801 [[STANDBY] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'] WARN org.hibernate.cfg.annotations.reflection.JPAOverridenAnnotationReader - Property com.foo.model.person.PersonContact.eAddress not found in class but described in (possible typo error) 2011-02-22 15:38:10,817 [[STANDBY] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'] WARN org.hibernate.cfg.annotations.reflection.JPAOverridenAnnotationReader - Property com.foo.model.person.PartyContact.eAddressCpId not found in class but described in (possible typo error) 2011-02-22 15:38:10,817 [[STANDBY] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'] WARN org.hibernate.cfg.annotations.reflection.JPAOverridenAnnotationReader - Property com.foo.model.person.PartyContact.eAddress not found in class but described in (possible typo error)
如果我将我的字段名称更改为electronicAddressCpId和electronicAddress,那么我不会收到这些警告。
字段名称是否有要求?
Thanks..jay
---------其他详情-------------------------------- 这是我的POJO的片段。
/**
* This is a generated class. Do not modify.
*/
@XmlRootElement(namespace = "http://foo.com/model", name = "ElectronicAddress")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(namespace = "http://foo.com/model", name = "ElectronicAddress", propOrder = { "eAddress", "id" })
public class ElectronicAddress extends ContactPoint {
/**
* The serialize value.
*/
private static final long serialVersionUID = -1L;
/**
* The eAddress field.
*/
@XmlElement(name = "EAddress", namespace = "##default")
private String eAddress;
/**
* The id field.
*/
@XmlElement(name = "Id", namespace = "##default")
private Long id; //NOPMD
/**
* Gets the value of the eAddress property.
* This field is Required.
*
* @return eAddress object is {@link String }
*/
public String getEAddress() {
return eAddress;
}
/**
* Sets the value of the eAddress property.
* This field is Required
*
* @param eAddress object is {@link String }
*/
public void setEAddress(String eAddress) {
this.eAddress = eAddress;
}
/**
* Gets the value of the id property.
* This field is Optional.
*
* @return id object is {@link Long }
*/
public Long getId() {
return id;
}
/**
* Sets the value of the id property.
* This field is Optional
* genericInheritGetterSetter
* @param id object is {@link Long }
*/
public void setId(Long id) {
this.id = (Long) id;
}
}
以下是orm文件的片段。
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm
http://java.sun.com/xml/ns/persistence/orm_2_0.xsd"
version="2.0">
<description>com.foo.model.ElectronicAddress Entity Mapping</description>
<package>com.foo.model</package>
<schema>COMMON</schema>
<access>FIELD</access>
<entity class="com.foo.model.ElectronicAddress"
access="FIELD" metadata-complete="true">
<table name="ELECTRONIC_ADDRESSES" />
<attributes>
<id name="id">
<column name="ELECTRONIC_ADDRESS_ID" />
<generated-value strategy="SEQUENCE" generator="ADDR_SEQ" />
<sequence-generator name="ADDR_SEQ"
sequence-name="COMMON.ADDR_SEQ" allocation-size="1" />
</id>
<basic name="eAddress">
<column name="ELECTRONIC_ADDRESS" />
</basic>
</attributes>
</entity>
</entity-mappings>
答案 0 :(得分:1)
这是来自JPAOverridenAnnotationReader
的相关代码(我使用的是3.5.6,但可能没有太大变化):
Element element = tree != null ? tree.element( "attributes" ) : null;
//put entity.attributes elements
if ( element != null ) {
//precompute the list of properties
//TODO is it really useful...
Set<String> properties = new HashSet<String>();
for (Field field : clazz.getFields()) {
properties.add( field.getName() );
}
for (Method method : clazz.getMethods()) {
String name = method.getName();
if ( name.startsWith( "get" ) ) {
properties.add( Introspector.decapitalize( name.substring( "get".length() ) ) );
}
else if ( name.startsWith( "is" ) ) {
properties.add( Introspector.decapitalize( name.substring( "is".length() ) ) );
}
}
for (Element subelement : (List<Element>) element.elements()) {
String propertyName = subelement.attributeValue( "name" );
if ( !properties.contains( propertyName ) ) {
log.warn( "Property {} not found in class"
+ " but described in <mapping-file/> (possible typo error)",
StringHelper.qualify( className, propertyName ) );
}
}
}
我没看到你描述的错误发生在哪里。
此代码:
for (Field field : clazz.getFields()) {
properties.add( field.getName() );
}
添加所有字段名称和此代码
if ( !properties.contains( propertyName ) ) {
log.warn( "Property {} not found in class"
+ " but described in <mapping-file/> (possible typo error)",
StringHelper.qualify( className, propertyName ) );
检查XML中映射的字段名称是否存在于类中。这些都不执行任何字符串处理(字符串处理仅针对方法)。我会说你在某处有拼写错误。
答案 1 :(得分:1)
我发现了问题,它是JPAOverridenAnnotationReader中checkForOrphanProperties方法的一部分:
for (Method method : clazz.getMethods()) {
String name = method.getName();
if ( name.startsWith( "get" ) ) {
properties.add( Introspector.decapitalize( name.substring( "get".length() ) ) );
}
else if ( name.startsWith( "is" ) ) {
properties.add( Introspector.decapitalize( name.substring( "is".length() ) ) );
}
}
问题是该方法查找所有公共字段,然后根据找到的“get”和“is”方法开始添加字段名称。 Introspector.decapitalize方法利用特定规则来确定什么是去资本化。
来自Introspector类:
/**
* Utility method to take a string and convert it to normal Java variable
* name capitalization. This normally means converting the first
* character from upper case to lower case, but in the (unusual) special
* case when there is more than one character and both the first and
* second characters are upper case, we leave it alone.
* <p>
* Thus "FooBah" becomes "fooBah" and "X" becomes "x", but "URL" stays
* as "URL".
*
* @param name The string to be decapitalized.
* @return The decapitalized version of the string.
*/
public static String decapitalize(String name) {
if (name == null || name.length() == 0) {
return name;
}
if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
Character.isUpperCase(name.charAt(0))){
return name;
}
char chars[] = name.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}
例如,我们的领域是:
private String eAddress;
我们的吸气剂是:
public String getEAddress() {
return eAddress;
}
因此,基于Introspector.decapitalize功能,decapitalize的结果将是“EAddress”,而不是“eAddress”。因为它在“EAddress”中看到两个大写字母,当代码从“获取”中减去...时它不会对那些进行去除资本化。因此它抱怨orm.xml中的eAddress字段不存在。该字段的持久性完全正常,这些警告只是在战争开始时出现并且文件被引导。