2013-07-24 2 views
0

EclipseLink이있는 JPA 엔티티에 static weaving을 사용하자마자 예외가 발생합니다.EclipseLink에서 작성한 엔티티의 스프링 데이터 -jpa 문제

응용 프로그램은 spring-data-jpaspring-data-rest-webmvc을 사용하여 엔티티를 변경하는 CRUD 기능을 제공하는 웹 응용 프로그램입니다.

엔터티 클래스가 위빙으로 처리되지 않으면 작동합니다. 하지만 최대한 빨리으로 짜 엔티티를 사용하여, 우리는 얻을 :

org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: 
Conflicting getter definitions for property "rootParentDescriptor": 
    org.eclipse.persistence.descriptors.InheritancePolicy#isRootParentDescriptor(0 params) vs org.eclipse.persistence.descriptors.InheritancePolicy#getRootParentDescriptor(0 params) (through reference chain: org.springframework.hateoas.Resources["content"]->java.util.UnmodifiableCollection[0]->org.eclipse.persistence.internal.descriptors.changetracking.AttributeChangeListener["descriptor"]->org.eclipse.persistence.descriptors.RelationalDescriptor["inheritancePolicy"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Conflicting getter definitions for property "rootParentDescriptor": org.eclipse.persistence.descriptors.InheritancePolicy#isRootParentDescriptor(0 params) vs org.eclipse.persistence.descriptors.InheritancePolicy#getRootParentDescriptor(0 params) (through reference chain: org.springframework.hateoas.Resources["content"]->java.util.UnmodifiableCollection[0]->org.eclipse.persistence.internal.descriptors.changetracking.AttributeChangeListener["descriptor"]->org.eclipse.persistence.descriptors.RelationalDescriptor["inheritancePolicy"]) 

..

JSON 응답은 엔터티를 포함하는 정렬 화되어야 할 때 발생
Caused by: java.lang.IllegalArgumentException: Conflicting getter definitions for property "rootParentDescriptor": org.eclipse.persistence.descriptors.InheritancePolicy#isRootParentDescriptor(0 params) vs org.eclipse.persistence.descriptors.InheritancePolicy#getRootParentDescriptor(0 params) 
at com.fasterxml.jackson.databind.introspect.POJOPropertyBuilder.getGetter(POJOPropertyBuilder.java:190) ~[jackson-databind-2.2.2.jar:2.2.2] 

.

<dependency> 
<groupId>org.springframework.data</groupId> 
<artifactId>spring-data-rest-webmvc</artifactId> 
<version>1.1.0.M1</version> 
</dependency> 

<dependency> 
<groupId>org.eclipse.persistence</groupId> 
<artifactId>org.eclipse.persistence.jpa</artifactId> 
<version>2.5.0</version> 
</dependency> 

<dependency> 
    <groupId>org.springframework.data</groupId> 
    <artifactId>spring-data-jpa</artifactId> 
    <version>1.3.2.RELEASE</version> 
</dependency> 

<dependency> 
    <groupId>com.fasterxml.jackson.core</groupId> 
    <artifactId>jackson-databind</artifactId> 
    <version>2.2.2</version> 
</dependency> 

이 조합 또는 이러한 문제를 설명하는 알려진 문제를 지원하는 구성이 있습니까 : 엔티티는 어떤 단체 등이 여기에

버전이 사용된다 단지 2 곳이 일반 간단하지?

답변

0

몇 가지 조사를 한 후에 해결 방법을 찾았지만 누군가가 더 나은 해결책을 알고있을 수도 있습니다. spring-data-commons의 JpaMetamodelMappingContext 클래스는 위빙 프로세스에 의해 추가 된 엔티티 클래스의 변수를 찾습니다. 이 필드는 EclipseLink의 내부 동작에만 관심이 있지만 메타 폰 (JpaPersistentEntity)에서 특성으로 수집합니다.

JpaMetamodelMappingContext를 자신의 하위 클래스로 바꿔 (예 : @Transient 인 경우처럼) 해당 필드가 수집되지 않도록했습니다. 이것은 HACK으로 수행되었습니다. 우리의 봄 구성에서

우리는 JPA에 공장 클래스를 추가 : 저장소

<jpa:repositories base-package="de.viaboxx.vplan.database.dao" 
        entity-manager-factory-ref="entityManagerFactory" 
        factory-class="de.viaboxx.springframework.data.jpa.EclipseJpaRepositoryFactoryBean"/> 

새로운 클래스 EclipseJpaRepositoryFactoryBean는 JpaMetamodelMappingContext의 새로운 구현을 소개합니다. 여기에 소스는 다음과 같습니다 (setEntityManager에 변화 JpaRepositoryFactoryBean에서 복사 클래스())

public class EclipseJpaRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends 
    TransactionalRepositoryFactoryBeanSupport<T, S, ID> { 

private EntityManager entityManager; 

/** 
* The {@link EntityManager} to be used. 
* 
* @param entityManager the entityManager to set 
*/ 
@PersistenceContext 
public void setEntityManager(EntityManager entityManager) { 
    this.entityManager = entityManager; 
    setMappingContext(
      new EclipseJpaMetamodelMappingContext(entityManager.getMetamodel())); // <<-- this is the only change 
} 

/* 
* (non-Javadoc) 
* 
* @see org.springframework.data.repository.support. 
* TransactionalRepositoryFactoryBeanSupport#doCreateRepositoryFactory() 
*/ 
@Override 
protected RepositoryFactorySupport doCreateRepositoryFactory() { 
    return createRepositoryFactory(entityManager); 
} 

/** 
* Returns a {@link RepositoryFactorySupport}. 
* 
* @param entityManager 
* @return 
*/ 
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) { 
    return new JpaRepositoryFactory(entityManager); 
} 

/* 
* (non-Javadoc) 
* 
* @see 
* org.springframework.beans.factory.InitializingBean#afterPropertiesSet() 
*/ 
@Override 
public void afterPropertiesSet() { 

    Assert.notNull(entityManager, "EntityManager must not be null!"); 
    super.afterPropertiesSet(); 
} 
} 

내부 속성을 필터링하는 해킹 클래스 EclipseJpaMetamodelMappingContext (패키지에 포함되어있는 'org.springframework.data.jpa해야합니다은. 매핑은 '클래스 JpaPersistentEntityImpl에 대한 액세스 권한을 받으실 수 있습니다!)

public class EclipseJpaMetamodelMappingContext extends JpaMetamodelMappingContext { 
/** 
* Creates a new JPA {@link javax.persistence.metamodel.Metamodel} based {@link org.springframework.data.mapping.context.MappingContext}. 
* 
* @param model must not be {@literal null}. 
*/ 
public EclipseJpaMetamodelMappingContext(Metamodel model) { 
    super(model); 
} 

@Override 
protected JpaPersistentProperty createPersistentProperty(Field field, PropertyDescriptor descriptor, 
                 JpaPersistentEntityImpl<?> owner, 
                 SimpleTypeHolder simpleTypeHolder) { 
    // HACK: ignore fields added by eclipselink weaving 
    // because they cause problems during JSON marshaling with spring-data-rest 1.1.0.M1 
    if (field.getType().getName().startsWith("org.eclipse.") || 
      field.getType().equals(PropertyChangeListener.class)) { 
     return new TransientPropertyToBeIgnored(field, descriptor, owner, simpleTypeHolder); 
    } else { 
     return super.createPersistentProperty(field, descriptor, owner, simpleTypeHolder); // call super! 
    } 
} 

static class TransientPropertyToBeIgnored extends AnnotationBasedPersistentProperty<JpaPersistentProperty> 
     implements JpaPersistentProperty { 

    @Override 
    public boolean isTransient() { 
     return true; // this causes the property to be ignored! 
    } 

    public TransientPropertyToBeIgnored(Field field, PropertyDescriptor propertyDescriptor, 
             PersistentEntity owner, 
             SimpleTypeHolder simpleTypeHolder) { 
     super(field, propertyDescriptor, owner, simpleTypeHolder); 
    } 

    @Override 
    protected Association createAssociation() { 
     return new Association<JpaPersistentProperty>(this, null); 
    } 
} 
} 

이 관계없이 길쌈 또는 unweaved 단체의, 우리를 위해 작동합니다.

EclipseLink 대신 Hibernate을 사용할 때 문제가 발생하지 않지만 최대 절전 모드를 사용하려면 jackson-hibernate-module 및 기타 구성이 변경되어야합니다.

+0

이 문제의 현재 상태는 springsource-jira를 참조하십시오. https://jira.springsource.org/browse/DATAJPA-376 – Roman

0

저는 fixed입니다. 지금 JPA @Transient 주석 속성을 일시적으로 고려하십시오. 따라서 퍼시스턴스 제공자가 올바르게 사용하는 퍼시스턴스 서비스를 사용하는 한 당신은 잘해야합니다. 그렇지 않은 경우 티켓을 제출해야합니다.

수정 사항은 Spring Data JPA의 1.3.5 및 1.4 RC1에서 사용할 수 있습니다.

관련 문제