2012-03-09 3 views
3

Я использую Play Framework 1.2.4 с Java и использую JPA для сохранения объектов моей базы данных. У меня есть несколько классов модели, которые будут отображаться как JSON. Но проблема в том, что я хотел бы настроить эти ответы JSON и упростить объекты непосредственно перед рендерингом как JSON.Play Framework: рендеринг пользовательских объектов JSON

Например, предположим, что у меня есть объект с именем ComplexClass и имеющий свойства id, name, property1, ..., propertyN. В ответе JSON я хотел бы отображать только поля id и name.

Что является самым элегантным способом сделать это? Написание пользовательских объектов связующего или простое сопоставление JSON, например, с использованием шаблона?

ответ

6

Используйте FlexJSON, это очень просто. Он позволяет создавать JSONSerializers, которые могут включать/исключать нужные поля.

Отъезд this article для некоторых примеров использования его с Play! Фреймворк.
Вот простой пример:

public ComplexClass { 
    public Long id; 
    public String name; 
    // And lots of other fields you don't want 

    public String toJsonString() { 
    // Include id & name, exclude all others. 
    JSONSerializer ser = new JSONSerializer().include(
      "id", 
      "name", 
    ).exclude("*"); 
    return ser.serialize(this); 
    } 

}

Вы можете добавить их к dependencies.yml так:

require: 
    - play 
    - net.sf.flexjson -> flexjson 2.1 

То, что я обычно делаю это написать интерфейс для моделей, инвентарем a toJSONString(), чтобы я мог вызвать renderJSON(someModel.toJSONString()) в контроллере.

Link to official website

EDIT: Дополнительный пример для списков/коллекция

Хорошо, когда вы начинаете сериализации списка вы можете получить неожиданные результаты. Это связано с тем, что оценка имеет значение. Первые include() или exclude() имеют приоритет над следующими.

Вот пример сериализации дочерних элементов родительского объекта (отношение OneToMany).

JSONSerializer ser = new JSONSerializer(); 
// Exclude these standard fields from childs 
ser.exclude(
    "*.persistent", 
    "*.class", 
    "*.entityId" 
); 
// Include childs and all its other fields 
ser.include(
    "childs", 
    "childs.*" 
); 
// Exclude everything else 
ser.exclude("*"); 
String data = ser.serialize(parent); 

* является шаблонных пути. Эта документация полностью объясняет это:
Исключить *.class будет соответствовать любой глубине пути. Поэтому, если flexjson сериализует поле с путём «foo.bar.class», * в *.class будет соответствовать foo.bar.

+1

Большое спасибо за ваш элегантный ответ. Я дам ему попробовать. FlexJson звучит хорошо, потому что гораздо проще создавать несколько представлений на одни и те же данные. – huzeyfe

+0

Кстати, (если возможно) вы могли бы подробно рассказать о своих деталях интерфейса, чтобы я мог также использовать этот способ для использования в контроллерах, поскольку мне нужно также сериализовать списки объектов. – huzeyfe

+1

Обновлено с примером для списков :) – maartencls

8

Play Framework 1.2.4 напрямую зависит от библиотеки gson, поэтому вы можете использовать ее для визуализации строк JSON. Все, что вам нужно сделать, это использовать аннотацию gson's @Expose. Таким образом, в вашем примере, вы бы отметить поля, которые вы хотите в вашем JSON строку, как это:

public class ComplexClass { 

    @Expose 
    public Long id; 

    @Expose 
    public String name; 

    ... 
} 

Тогда в контроллере, вы бы просто сделать это:

public static void someActionMethod() { 
    // get an instance of your ComplexClass here 
    ComplexClass complex = ... 
    Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create() 
    String json = gson.toJson(complex); 
    renderJson(json); 
} 

См документации here.

Если ComplexClass фактически play.db.jpa.Model и поэтому id поля абстрагируется в родительском классе, и вы не можете поместить @Expose аннотации на него, то вы можете создать свой собственный ExclusionStrategy, что скачет поля, которые не аннотированные с @Expose и не называются id. Так что-то вроде этого (псевдо-код):

public final class ComplexClassExclusionStrategy implements ExclusionStrategy { 

    public boolean shouldSkipField(FieldAttributes attributes) { 
     if (name of field is "id") return false; 
     if (field is annotated with @Expose) return false; 
     return true; 
    } 

Затем контроллер будет немного изменен, чтобы выглядеть следующим образом:

GsonBuilder builder = new GsonBuilder(); 
    ComplexClassExclusionStrategy strategy = new ComplexClassExclusionStrategy(); 
    builder.setExclusionStrategies(strategy); 
    Gson gson = builder.create(); 
    String json = gson.toJson(complex); 
    renderJson(json); 
+0

Огромное спасибо вашему подробному ответу. Это хороший подход, если вы не хотите добавлять новые библиотеки в свой проект, поскольку Play уже использует библиотеку Gson. Однако я думаю, что лучше использовать FlexJson в моем случае. Во всяком случае, я буду иметь в виду этот ответ. Благодарю. – huzeyfe

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