В Hibernate / JPA имена полей не могут начинаться с одной буквы? - PullRequest
2 голосов
/ 23 марта 2011

Я использую 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, то я не получу эти предупреждения.* Существуют ли требования к именам полей?

Спасибо .. Сойка

--------- Дополнительные детали -------------------------------- Вот фрагмент моего 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 ]

1 голос
/ 26 января 2012

Я обнаружил проблему, и она является частью метода checkForOrphanProperties в JPAOverridenAnnotationReader:

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, результатом декапитализации будет «EAddress», а не «eAddress». Поскольку он видит две заглавные буквы в «EAddress», когда код подстрокует от «get» ... он не будет декапитализирован. Поэтому он жалуется, что поле eAddress в orm.xml не существует. Постоянство поля работает совершенно нормально, эти предупреждения просто появляются, когда начинается война и файлы загружаются.

1 голос
/ 23 марта 2011

Это соответствующий код из 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, в классе,Ни одна из них не выполняет никакой обработки строк (обработка строк выполняется только для методов).Я бы сказал, что у вас есть опечатка где-то.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...