web-dev-qa-db-ja.com

jackson-怠惰なオブジェクトをシリアル化しない

私はエンティティを持っています:

@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;

}

次に、本を取得することを目的としたコントローラーがあります。問題は、コントローラーのjson応答にジャンルフィールドが含まれていることです。 jacksonがオブジェクトをシリアル化するときに遅延ロードされるフィールドを除外する方法はありますか?

これは私のObjectMapperの構成です:

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

ありがとう!

シリアル化ボックスから永久に外れるため、JsonIgnoreとしてマークすることはできません。本と一緒にジャンルを取得する必要がある場合があります。それまでに、クエリで「フェッチ結合」を使用して、nullにならないようにします。

9
lorrainebatol

あなたはジャクソンでこれを行うことができます@JsonInclude注釈。

最新バージョンのjavadoc(現在は2.4) によると、フィールド値がnullまたは空の場合に、注釈付きプロパティを含めるかどうかを簡単な注釈で指定できます。

デフォルトでは、JsonInclude.Include.ALWAYS、これは、レイジーにロードされていない値がnullであっても、Jacksonにプロパティが含まれていることを意味します。

空の値またはnull値を含めないように指定すると、JSON応答のサイズを大幅に削減でき、すべての利点が含まれます。

この動作を変更する場合は、クラスレベルまたは単一のproperty/getterMethodレベルでアノテーションを追加できます。

空の場合に含めたくないフィールドに次の注釈を追加してみてください。

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

JacksonのJSONフィルター機能 を使用できます:

@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 {
   ...
}

次に、コントローラーで何をフィルターするかを指定します。

@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)
       }

}

このようにして、実行時に遅延関係をフィルタリングするタイミングを制御できます。

3

多分これは 遅延読み込みに関する既知の問題 に関連しています。

私はjackson-datatype-hibernateを使用しませんが、同じ問題を解決するために行ったことは、Hibernateオブジェクトを直接シリアル化する代わりに、DTOを使用して永続コレクションを画像から取得することです。 Dozerのようなツールはそれを助けることができます。あるいは、 小さなユーティリティ このようなマッピングを行うために書いたものがあります。

DTOがどのように見えるかを実験したいだけの場合は、アンロードされた永続コレクションを、books.setGenre(new ArrayList <>());のような通常の空のコレクションに置き換えることができます。残念ながら、遅延ロードされたオブジェクトがロードされたかどうかを確認する方法がわからないため、この再割り当てを自動的に行うことはできません。永続的なコレクションを置き換える場所は、ケースバイケースで決定する必要があります。

1
Jay