在Hibernate / JPA中,字段名称不能以单字母驼峰字母开头吗?

时间:2011-03-23 17:01:01

标签: java hibernate jpa jpa-2.0

我使用的是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>

2 个答案:

答案 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字段不存在。该字段的持久性完全正常,这些警告只是在战争开始时出现并且文件被引导。