5

Я пытаюсь понять, почему я получаю сообщение об ошибке с некоторыми вызовами GET, а не другими с Google Engine Engine Entity.Понимание исключения JsonMappingException с конечной точкой Google

Класс

@Entity 
public class Client { 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private Key id; 
    private String firstName; 
    private String lastName; 

    @Basic(fetch = FetchType.EAGER) 
    @ElementCollection 
    private List<Assessment> assessment; 

    public List<Assessment> getAssessment() { 
     return assessment; 
    } 

    public void setAssessment(List<Assessment> assessment) { 
     this.assessment = assessment; 
    } 
} 

Работы

И если я использую list запрос, он отлично работает.

GET http://localhost:8888/_ah/api/clientendpoint/v1/client 

В результате, как ожидается,

{ 
"items": [ 
    { 
    "id": { 
    "kind": "Client", 
    "appId": "no_app_id", 
    "id": "12", 
    "complete": true 
    }, 
    "firstName": "Jane", 
    "lastName": "Doe" 
    }, 
    { 
    "id": { 
    "kind": "Client", 
    "appId": "no_app_id", 
    "id": "13", 
    "complete": true 
    }, 
    "firstName": "Jon", 
    "lastName": "Doe", 
    } 
] 
} 

Не работает

Но если я получаю только 1 запись, например, выбрать идентификатор 12, производится ошибка

GET http://localhost:8888/_ah/api/clientendpoint/v1/client/12 

com.google.appengine.repackaged.org.codehaus.jackson.map.JsonMappingException: Вы только что попытались получить доступ к поле «оценка», но это поле не было отсоединено, когда вы отсоединили объект. Либо не обращайтесь к этому полю , либо отсоединяйте его при отсоединении объекта. (через ссылку цепочка: com.google.api.server.spi.response.CollectionResponse [\ "items \"] -> com.google.appengine.datanucleus.query.StreamingQueryResult [0] -> com.my.app .client.Client [\ «оценка \»])

работы, если я удалю методы получения/установки

Где я запутался, если я закомментируйте setAssessment(...) и getAssesment() методы внутри Client Объект, он отлично работает.

@Entity 
public class Client { 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private Key id; 
    private String firstName; 
    private String lastName; 

    @Basic(fetch = FetchType.EAGER) 
    @ElementCollection 
    private List<Assessment> assessment; 

    //public List<Assessment> getAssessment() { 
    // return assessment; 
    //} 

    //public void setAssessment(List<Assessment> assessment) { 
    // this.assessment = assessment; 
    //} 
} 

Он отлично работает

GET http://localhost:8888/_ah/api/clientendpoint/v1/client/12 

Результат

{ 
"id": { 
    "kind": "Client", 
    "appId": "no_app_id", 
    "id": "12", 
    "complete": true 
}, 
"firstName": "Jane", 
"lastName": "Doe" 
} 

Мои вопросы

  • Почему это работает, когда я закомментируйте получить/установить
  • Как правильно исправить это?
  • У меня возникли проблемы с поиском хороших примеров кода для кода Java App Engine, кроме простых примеров в документах. Кто-нибудь знает какие-нибудь хорошие примеры?

Соответствующий Endpoint код

/** 
* 
* This method works fine 
* 
*/ 
@SuppressWarnings({ "unchecked", "unused" }) 
@ApiMethod(name = "listClient") 
public CollectionResponse<Client> listClient(
     @Nullable @Named("cursor") String cursorString, 
     @Nullable @Named("limit") Integer limit) { 

    EntityManager mgr = null; 
    Cursor cursor = null; 
    List<Client> execute = null; 

    try { 
     mgr = getEntityManager(); 
     Query query = mgr.createQuery("select from Client as Client"); 
     if (cursorString != null && cursorString != "") { 
      cursor = Cursor.fromWebSafeString(cursorString); 
      query.setHint(JPACursorHelper.CURSOR_HINT, cursor); 
     } 

     if (limit != null) { 
      query.setFirstResult(0); 
      query.setMaxResults(limit); 
     } 

     execute = (List<Client>) query.getResultList(); 
     cursor = JPACursorHelper.getCursor(execute); 
     if (cursor != null) 
      cursorString = cursor.toWebSafeString(); 

    } finally { 
     mgr.close(); 
    } 

    return CollectionResponse.<Client> builder().setItems(execute) 
      .setNextPageToken(cursorString).build(); 
} 

/** 
* 
* This method errors out 
* 
*/ 
@ApiMethod(name = "getClient") 
public Client getClient(@Named("id") Long id) { 
    EntityManager mgr = getEntityManager(); 
    Client client = null; 
    client = mgr.find(Client.class, id); 
    mgr.close(); 
    return client; 
} 
+0

На первый взгляд это похоже на проблему с ленивой загрузкой, но я не уверен. У вас есть 'оценка', установленная в значение, отличное от нуля, в любом из ваших объектов? Он не показывает значение в вашем примере 'list', я просто хочу убедиться, что это точно. –

+0

Я еще ничего не ввел в «оценку». Не все сущности будут иметь их. Нужно ли просто инициализировать 'оценку' внутри конструктора? – Kirk

+0

Нет, я просто проверял, что отсутствие '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' это не ошибка. Мне придется поиграть с этим немного, чтобы понять, что случилось. –

ответ

4

я столкнулся с той же проблемой, и это, безусловно, отложенной загрузки вопрос:

@ApiMethod(name = "getClient") 
public Client getClient(@Named("id") Long id) { 
    EntityManager mgr = getEntityManager(); 
    Client client = mgr.find(Client.class, id); 
    if (client != null) 
     client.getAssessment(); // Forces it to load your objects 
    mgr.close(); 
    return client; 
} 

К сожалению, я не смог найти более рациональный способ чтобы исправить это, поэтому, пожалуйста, дайте мне знать, если у вас есть лучшие альтернативы! Одна из последних вещей: мне также хотелось бы знать, почему она ведет себя по-другому, когда Кирк комментирует геттеры/сеттеры.

EDIT 26/12/2013:
Похоже, что выборки типов теперь работает правильно, используя последнюю версию App Engine + DataNucleus. Я также нашел очень интересное поведение:

  • Если вы используете TypedQuery<T> вместо Query, JPA будет пытаться загрузить все области T (он игнорирует FetchType.LAZY), и вы получите JsonMappingException, если эти поля не были вручную загружен.
  • Если вы используете Query, JPA будет загружать только поля, отмеченные как FetchType.EAGER, поэтому следите за исключениями, если вы собираетесь использовать поля, отмеченные как ленивые, но не загруженные должным образом.
+1

Кроме того, FetchType.EAGER, похоже, игнорируется в соответствии с https://groups.google.com/forum/?fromgroups#!topic/google-appengine-java/Mk3-yaqnJxQ –

+0

Да, хороший звонок. Похоже, мой совет использовать 'EAGER' был недействительным. Для метода 'list' имеется несколько строк, отсутствующих в фрагменте выше' for (Lazy obj: execute) 'выполняет загружаемую загрузку в методе списка. Вам нужно будет выполнить подцикл 'for (Оценка оценки: obj.getAssessment())', чтобы с нетерпением загрузить это свойство. –

+0

Я рассмотрю это позже сегодня, когда я с кодом. Спасибо за помощь. – Kirk

Смежные вопросы