2014-12-13 2 views
0

스프링 데이터 REST/RestRepository 아키텍처를 사용하는 간단한 개념 증명 데모가 있습니다.@OneToMany에 대한 REST를 통한 JSON 반환이 예외 (이전의 NullPointer) 예외

@Entity 
@org.hibernate.annotations.Proxy(lazy=false) 
@Table(name="Address") 
public class Address implements Serializable { 

    public Address() {} 

    @Column(name="ID", nullable=false, unique=true) 
    @Id 
    @GeneratedValue(generator="CUSTOMER_ADDRESSES_ADDRESS_ID_GENERATOR")  
    @org.hibernate.annotations.GenericGenerator(name="CUSTOMER_ADDRESSES_ADDRESS_ID_GENERATOR", strategy="native") 
    private int ID; 

    //@RestResource(exported = false) 
    @ManyToOne(targetEntity=domain.location.CityStateZip.class, fetch=FetchType.LAZY) 
    @org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.PERSIST}) 
    @JoinColumns({ @JoinColumn(name="CityStateZipID", referencedColumnName="ID", nullable=false) }) 
    private domain.location.CityStateZip cityStateZip; 

    @Column(name="StreetNo", nullable=true) 
    private int streetNo; 

    @Column(name="StreetName", nullable=false, length=40) 
    private String streetName; 

    <setters and getters ommitted> 
} 

CityStateZip에 대한 : 저장소에

@Entity 
@org.hibernate.annotations.Proxy(lazy=false) 
@Table(name="CityStateZip") 
public class CityStateZip { 

    public CityStateZip() {} 

    @Column(name="ID", nullable=false, unique=true) 
    @Id 
    @GeneratedValue(generator="CUSTOMER_ADDRESSES_CITYSTATEZIP_ID_GENERATOR") 
    @org.hibernate.annotations.GenericGenerator(name="CUSTOMER_ADDRESSES_CITYSTATEZIP_ID_GENERATOR", strategy="native") 
    private int ID; 

    @Column(name="ZipCode", nullable=false, length=10) 
    private String zipCode; 

    @Column(name="City", nullable=false, length=24) 
    private String city; 

    @Column(name="StateProv", nullable=false, length=2) 
    private String stateProv; 

} 

:

@RepositoryRestResource(collectionResourceRel = "addr", path = "addr") 
public interface AddressRepository extends JpaRepository<Address, Integer> { 

    List<Address> findByStreetNoAndStreetNameStartingWithIgnoreCase(@Param("stNumber") Integer streetNo, @Param("street") String streetName); 
    List<Address> findByStreetNameStartingWithIgnoreCase(@Param("street") String streetName); 
    List<Address> findByStreetNo(@Param("streetNo") Integer strNo); 
} 

과 :

// @RepositoryRestResource(collectionResourceRel = "zip", path = "zip", exported = false) 
@RepositoryRestResource(collectionResourceRel = "zip", path = "zip") 
public interface CityStateZipRepository extends JpaRepository<CityStateZip, Integer> { 

    List<CityStateZip> findByZipCode(@Param("zipCode") String zipCode); 
    List<CityStateZip> findByStateProv(@Param("stateProv") String stateProv); 
    List<CityStateZip> findByCityAndStateProv(@Param("city") String city, @Param("state") String state); 
} 

의 주() 코드 나는 두 엔티티 시작
@Configuration 
@EnableJpaRepositories 
@Import(RepositoryRestMvcConfiguration.class) 
@EnableAutoConfiguration 
// @EnableTransactionManagement 
@PropertySource(value = { "file:/etc/domain.location/application.properties" }) 
@ComponentScan 
public class Application { 

    public static void main(String[] args) { 
     SpringApplication.run(Application.class, args); 
    } 
} 

이 코드를 사용하면 문제가 없습니다. CityStateZip을 저장하고 주소를 저장하는 동안 참조 할 수 있으며 결과 주소를 얻을 수 있습니다. 두 번째 단계는 다른 클래스를 추가하는 것이 었습니다. Address는 0에서 많은 수의 Remarks를 가질 수 있고 Remark은 하나의 Address와 묶일 수 있습니다.

@Entity 
@org.hibernate.annotations.Proxy(lazy=false) 
@Table(name="Remark") 
@SuppressWarnings({ "all", "unchecked" }) 
public class Remark implements Serializable { 
    public Remark() { 
    } 

    @Column(name="ID", nullable=false) 
    @Id 
    @GeneratedValue(generator="CUSTOMER_ADDRESSES_REMARK_ID_GENERATOR") 
    @org.hibernate.annotations.GenericGenerator(name="CUSTOMER_ADDRESSES_REMARK_ID_GENERATOR", strategy="native") 
    private int ID; 

    @ManyToOne(targetEntity=domain.location.Address.class, fetch=FetchType.LAZY)  
    @org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.LOCK})  
    @JoinColumns({ @JoinColumn(name="LocationID", referencedColumnName="ID", nullable=false) }) 
    private domain.location.Address address_ix; 

    @Column(name="Comment", nullable=false, length=255) 
    private String comment; 

    <getters, setters removed> 
} 

및 저장소 : 그 실체는

@RepositoryRestResource(collectionResourceRel = "remarks", path = "remarks") 
public interface RemarkRepository extends JpaRepository<Remark, Integer> { 
} 

나는이 주소에 추가 :

@OneToMany(mappedBy="address_ix", targetEntity=domain.location.Remark.class)  
@org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.LOCK}) 
@org.hibernate.annotations.LazyCollection(org.hibernate.annotations.LazyCollectionOption.TRUE) 
private java.util.Set remark = new java.util.HashSet(); 

나는 GET .../요지 수행하여 노출 된 API를 검색 할 수 있습니다 Address 인스턴스가없는 경우. 주소 인스턴스를 데이터베이스에 저장할 수 있습니다.

"timestamp": 1418423263313, 
"status": 500, 
"error": "Internal Server Error", 
"exception": "org.springframework.http.converter.HttpMessageNotWritableException", 
"message": "Could not write JSON: (was java.lang.NullPointerException) (through reference chain: org.springframework.hateoas.PagedResources[\"_embedded\"]->java.util.UnmodifiableMap[\"addr\"]->java.util.ArrayList[0]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: org.springframework.hateoas.PagedResources[\"_embedded\"]->java.util.UnmodifiableMap[\"addr\"]->java.util.ArrayList[0])", 
"path": "/addr" 

나는 내가 @OneToMany 협회에서 뭔가 잘못을하고있는 중이 야 가정 : 나는 저장된 인스턴스가하지만 일단하는 GET을하고 .../요지, 또는 특정 인스턴스를 얻으려고, 나는 예외가 주소 또는 Remark에 @ManyToOne 또는이 두 가지를 조합하십시오. @ManyToOne, 주소에 대한 단방향 연결을 문제없이 추가했습니다. GET을 통해 주소 데이터를 가져올 수 있으려면 어떻게해야합니까? JSON은 무엇에 대해 불평하고 있습니까? (이 시점에서 데이터베이스에는 Remark 인스턴스가 없었고 @OneToMany 앞에 @JsonIgnore 주석을 추가 했는데도 여전히 오류가 발생했습니다.

답변

0

이 문제는 자동 응답으로 인한 것입니다. 내가

@OneToMany(mappedBy="address_ix", targetEntity=domain.location.Remark.class)  
@org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.LOCK}) 
@org.hibernate.annotations.LazyCollection(org.hibernate.annotations.LazyCollectionOption.TRUE) 
private java.util.Set<Remark> remark = new java.util.HashSet<Remark>(); 

에 코드를 변경하는 경우 생성 된 코드. 발언의 설정의 선언. 세트 (또는 HashSet의)의 유형을 호출 매개 변수를 누락 된 코드 이제 매개 변수가 없으면. 필요에 따라 작동의 (Spring 또는 JSON) 코드는이 멤버를 처리하는 방법을 알지 못했습니다.