2011-03-23 110 views
2

我使用的是Hibernate 3.6,JPA 2.0和Spring 3.0.6。我在我的对象,如以下字段:在Hibernate/JPA中,字段名称是否以单个字母驼峰开头?

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,然后我没有得到这些警告。

围绕字段名称有要求吗?

谢谢.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> 

回答

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”和字段名“是“它找到的方法。 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功能,资产不足的结果将是“电子地址”,而不是“电子地址”。因为当代码从“获得”中抽出时,它会在“EAddress”中看到两个大写字母......它不会使这些字母去除数据。因此它抱怨orm.xml中的eAddress字段不存在。该领域的持久性工作完全正常,这些警告只是在战争开始时以及启动文件时出现。

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映射字段名的类存在。这些都没有做任何字符串处理(字符串处理只对方法完成)。我会说你在某个地方有一个错字。

+0

我花了相当多的时间来回应,但这绝对不是我们在生产中运行时的错字,所有Hibernate持久化都能成功运行,而且orm文件是由代码生成的,而不是开发人员操纵的,我们只是获取这些消息(每个以小写字母开头的字段至少大约60+)。此外,我没有使用注释,我使用HBM文件......这是否有差异。 – 2012-01-25 20:16:40