본문 바로가기

Cloud/GAE

GAE/J(Google App Engine for Java)에서 JPA를 사용할 때 지원되지 않는 것들

GAE/J와 DataStore(DataNuclues)를 접한지 일주일이 되었다.
처음엔 Maven을 적용하나라 고생했고 다음엔 Spring + Struts2를 적용하느라 삽질하고
이제좀 적응되려나 싶었는데 JPA때문에 또 힘들어 졌다.

Unsupported Features of JPA

The following features of the JPA interface are not supported by the App Engine implementation:

  • Owned many-to-many relationships, andunowned relationships. You can implement unowned relationships usingexplicit Key values, though type checking is not enforced in the API.
  • "Join"queries. You cannot use a field of a child entity in a filter whenperforming a query on the parent kind. Note that you can test theparent's relationship field directly in query using a key.
  • Aggregation queries (group by, having, sum, avg, max, min)
  • Polymorphicqueries. You cannot perform a query of a class to get instances of asubclass. Each class is represented by a separate entity kind in thedatastore.

http://code.google.com/intl/ko-KR/appengine/docs/java/datastore/usingjpa.html#Unsupported_Features_of_JPA 참고

이런 문제가 있다고 하니 이정도는 감수하려고 했다. 그런데 진행도중 다름과 같은 예외가 발생한다는 것을 디버깅해서(예외를 던져주지 않아서...) 알게 되었다.

Problem with query <SELECT count(entity.name) cnt FROM NameCard entity WHERE entity.name LIKE :name>: Unsupported method <matches> while parsing expression: InvokeExpression{[PrimaryExpression{name}].matches(ParameterExpression{name})}

위의 JPQL은 그닥 어렵지 않은 쿼리이다. 그런데 왜 동작하지 않을까?...
열심히 구글링을 한 결과 DataStore 라는 BigTable은 LIKE를 지원하지 않는다고 한다.

http://blog.newsplore.com/2009/06/06/reviewing-google-appengine-for-java-part-2

를 참고하기 바란다.

위의 사이트 내용중 DataStore의 제한사항(limitation)을 보면 아래와 같다.

1. LIKE 지원 안함
org.datanucleus.store.appengine.query.DatastoreQuery$UnsupportedDatastoreFeatureException:Problem with query : Unsupported method <upper> while parsing expression: InvokeExpression {[null].upper(PrimaryExpression {station, usState})}

org.datanucleus.store.appengine.query.DatastoreQuery$UnsupportedDatastoreOperatorException:Problem with query <SELECT station FROM com.newsplore.weather.bo.Station station WHERE UPPER(station.name) LIKE :stationName ORDER BY station.name>: App Engine datastore does not support operator  LIKE

2. PK로 int 타입을 사용할 수 없다. (내가 해본결과 long 타입도 안된다.) Long 으로 대체해야만한다.
3. JPA 쿼리는 클래의 완전한 경로명을 필요로 한다. select의 from 절에 사용할 때(지금은 약식명(SimpleName)을 사용해도 된다.)
4. 처음으로 어떤 엔티티를 액세스할때 일치하지 않는 NullPointerException이 발생한다.
ERROR MainHandlerExceptionResolver:18  Exception processing page: Name is null
java.lang.NullPointerException: Name is null
    at java.lang.Enum.valueOf(Enum.java:195)
    at com.google.appengine.api.datastore.dev.
CompositeIndexManager$IndexSource.valueOf(CompositeIndexManager.java:64)

이후 엔티티를 재요청하면 정상 페치된다.

5. 복합키를 수락하지 않는다. <== 요거는 확인해 봐야 겠다.  안되면 안되는데...
6. java.sql.TImestamp를 지원하지 않는다. 아래예외는 해당타입을 포함한 엔티티를 액세스할 때 발생한 것이다.
nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: java.sql.Timestamp is not a supported property type.; nested exception is java.lang.IllegalArgumentException: java.sql.Timestamp is not a supported property type.]

7. 유니크 제약(uniqueness constraints)을 지원하지 않는다.
8. @ManyToOne 관계를 생성할 수 없다. <== 음 난 생성되었는데 좀더 해봐야 겠다.
9. Not equals(<>, !=)와 IN 연산자를 지원하지 않는다. <== 정말??.. IN은 그렇다쳐도

위의 내용을 내가 모두 테스트한 것은 아니므로 정말 모두 안되는지는 잘 모르겠다.
참고한 글이 쓰여진때가 2009.06.06 인걸로 보면 지금으로부터 3개월 전의 내용인데
제법 일치하지 않을까 조심스럽게 판단해본다.
위의 내용이 사실이 아니기를 아니면 언젠가 지원된다는 희망이라도 있었으면 하는 바램이다.