2014-09-18 13 views
6

Ich habe eine Einheit:jackson - serialisieren nicht faul Objekte

@Entity 
public class Book { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 

    @Column 
    private String title; 

    @OneToMany(fetch = FetchType.LAZY, mappedBy = ("movie"),cascade = CascadeType.ALL) 
    private List<Genre> genre; 

} 

Dann habe ich einen Controller, dessen Zweck es ist, Bücher zu holen, mein Problem ist, dass das Genre-Feld in der JSON-Antwort enthalten ist der mein Controller. Kann ich die Felder, die faul geladen sind, ausschließen, wenn Jackson das Objekt serialisiert? Diese

ist die Konfiguration meines ObjectMapper:

Hibernate4Module hm = new Hibernate4Module(); 
hm.configure(Hibernate4Module.Feature.FORCE_LAZY_LOADING, false); 
registerModule(hm); 
configure(SerializationFeature.INDENT_OUTPUT, true); 

Dank!

Ich kann es nicht als JsonIgnore markieren, wie es für immer aus der Serialisierungsbox sein wird. Es wird Zeiten geben, in denen ich die Genres zusammen mit dem Buch abrufen muss, und bis dahin werde ich "Fetch Join" für meine Abfrage verwenden, damit es nicht null ist.

+0

[Transient] [1] [1]: http://stackoverflow.com/ Fragen/20700530/Why-Use-Transient-Keyword-in-Java Versuchen Sie mit diesem Thema, um Ihre anserw;) – Fincio

+0

Hi @Fincio, kann ich nicht Genre-Feld als transient, wie ich es auf der Datenbank. – lorraine

+0

Hmmm, wie wäre es mit @JsonIgnoreProperties ({"genre"}) oder @JsonIgnore – Fincio

Antwort

7

Sie können dies mit der Jackson @JsonInclude Annotation tun.

Entsprechend der latest version's javadoc (2.4 right now) können Sie mit einer einfachen Anmerkung angeben, ob die annotierte Eigenschaft enthalten oder nicht, wenn der Feldwert null oder leer ist.

Standardmäßig ist es JsonInclude.Include.ALWAYS, und das bedeutet, dass selbst wenn Ihre faul geladenen Werte null sind, Jackson die Eigenschaft enthält.

Angeben nicht leer oder Nullwerte enthalten kann, die Größe der JSON-Antwort signifikant reduzieren, mit allen enthaltenen Vorteile ..

Wenn Sie dieses Verhalten ändern möchten, können Sie die Anmerkung an Klasse hinzufügen -Ebene oder einzelne Eigenschaft/GetterMethod-Ebene.

Versuchen Sie, die folgenden Anmerkungen zu den Feldern hinzufügen, die Sie nicht wollen, schließen, wenn leer:

@JsonInclude(JsonInclude.Include.NON_EMPTY) 
@OneToMany(fetch = FetchType.LAZY, mappedBy = ("movie"),cascade = CascadeType.ALL) 
private List<Genre> genre; 
+2

Dies funktioniert bei mir nicht für eine Spring JPA + Spring REST Controller-Lösung. Das faule Holen tritt immer noch auf, wenn die JSON-Serialisierung stattfindet ... –

+0

Dies ist nicht die richtige Antwort für JPA 2.1 in Kombination mit EclipseLink! Das Problem ist offensichtlich, dass Jackson die Eigenschaften für "NON_EMPTY" überprüft, indem er die Getter aufruft und das Lazy Loading! Leider gibt es keine JSON-Annotation "Feld" von AccesType oder so, das würde helfen. Dies wird übrigens von Moxy unterstützt (ich denke, dass JAXB-Annotationen dafür verwendet werden). – Nabi

+0

@RonyeVernaes funktioniert es nach dem Hinzufügen einer 'Hibernate5Module' Bean. Bitte lesen Sie chrismarx 'Antwort in http://stackoverflow.com/questions/21708339/avoid-jackson-serialization-on-n-fetched-lazy-objects. – Zeemee

1

Vielleicht hängt das mit a known issue about lazy loading zusammen.

Ich benutze nicht jackson-datatype-hibernate, aber was ich getan habe, um das gleiche Problem zu lösen, ist die persistente Sammlung aus dem Bild mit einem DTO, anstatt ein Hibernate-Objekt direkt zu serialisieren. Tools wie Dozer können Ihnen dabei helfen. Alternativ dazu gibt es eine small utility, die ich geschrieben habe, um solche Abbildungen zu machen.

Wenn Sie nur ausprobieren möchten, wie ein DTO aussehen könnte, können Sie die entladene persistente Sammlung durch eine normale leere Sammlung ersetzen, wie books.setGenre (new ArrayList <>()); Leider weiß ich nicht, wie man feststellen kann, ob ein träge geladenes Objekt geladen wurde oder nicht, so dass Sie diese Neuzuweisung nicht automatisch durchführen können. Die Orte, an denen Sie persistente Sammlungen ersetzen, müssen von Fall zu Fall bestimmt werden.

2

können Sie Jackson's JSON Filter Feature verwenden:

@Entity 
@JsonFilter("Book") 
public class Book { 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 

    @Column 
    private String title; 

    @OneToMany(fetch = FetchType.LAZY, mappedBy = ("movie"),cascade = CascadeType.ALL) 
    private List<Genre> genre; 
} 

@Entity 
@JsonFilter("Genre") 
public class Genre { 
    ... 
} 

dann im Controller geben Sie etwas zu filtern:

@Controller 
public class BookController { 
     @Autowired 
     private ObjectMapper objectMapper; 

     @Autowird 
     private BookRepository bookRepository; 

     @RequestMapping(value = "/book", method = RequestMethod.GET, produces = "application/json") 
     @ResponseBody 
     public ResponseEntity<String> getBooks() { 

      final List<Book> books = booksRepository.findAll(); 
      final SimpleFilterProvider filter = new SimpleFilterProvider(); 
      filter.addFilter("Book", SimpleFilterProvider.serializeAllExcept("Genre"); 
      return new ResponseEntity<>(objectMapper.writer(filter).writeValueAsString(books), HttpStatus.OK) 
     } 

} 

Auf diese Weise können Sie steuern, wenn Sie die faule Beziehung zur Laufzeit filternde

+0

Da Bearbeitungswarteschlange jetzt voll ist, sollte ich eine Zeile korrigieren; Das zweite Argument von addFilter() sollte ** SimpleBeanPropertyFilter ** sein. serializeAll ... not ** SimpleFilterProvider **. serializeAll ... class –

Verwandte Themen