14

我有一个实体:

@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 响应中。当杰克逊序列化对象时,我有什么办法可以排除那些延迟加载的字段?

这是我的 ObjectMapper 的配置:

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

谢谢!

我不能将它标记为 JsonIgnore,因为它将永远脱离序列化框。有时我需要检索书籍的类型,到那时我将在我的查询中使用“fetch join”,这样它就不会为空。

4

5 回答 5

12

您可以使用 Jackson@JsonInclude注释来执行此操作。

根据最新版本的 javadoc(现在为 2.4),如果字段值为 null 或为空,您可以使用简单的注释指定是否包含带注释的属性。

默认情况下,它是JsonInclude.Include.ALWAYS,这意味着即使您的延迟未加载值为 null,Jackson 也会包含该属性。

指定不包含空值或 null 值可以显着减小 JSON 响应的大小,并包含所有好处。

如果要更改此行为,可以在类级别或单个属性/getterMethod 级别添加注释。

尝试将以下注释添加到您不想包含的字段(如果为空):

@JsonInclude(JsonInclude.Include.NON_EMPTY)
@OneToMany(fetch = FetchType.LAZY, mappedBy = ("movie"),cascade = CascadeType.ALL)
private List<Genre> genre;
于 2014-09-29T09:49:37.810 回答
2

您可以使用杰克逊的 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", SimpleBeanPropertyFilter.serializeAllExcept("genre");
          return new ResponseEntity<>(objectMapper.writer(filter).writeValueAsString(books), HttpStatus.OK)
       }
      
}

这样,您可以控制何时要在运行时过滤惰性关系

于 2014-09-18T16:51:59.837 回答
1

也许这与关于延迟加载的已知问题有关

我不使用jackson-datatype-hibernate,但我为解决同样的问题所做的是通过使用DTO而不是直接序列化Hibernate对象来使持久性集合脱离图片。像推土机这样的工具可以帮助你解决这个问题。或者,我写了一个小工具来做这样的映射。

如果您只是想试验一下 DTO 的外观,可以将卸载的持久性集合替换为常规的空集合,例如 books.setGenre(new ArrayList<>()); 不幸的是,我不知道如何判断是否已加载延迟加载的对象,因此您无法自动执行此重新分配。您需要根据具体情况确定替换持久性集合的位置。

于 2014-09-18T11:56:47.957 回答
1

您可以使用弹簧配置默认禁用强制延迟加载!

@Configuration
public class JacksonConfig {
    
    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        Hibernate5Module hibernate5Module = new Hibernate5Module();
        hibernate5Module.configure(Feature.FORCE_LAZY_LOADING, false);
        // Enable below line to switch lazy loaded json from null to a blank object!
        //hibernate5Module.configure(Feature.SERIALIZE_IDENTIFIER_FOR_LAZY_NOT_LOADED_OBJECTS, true);
        mapper.registerModule(hibernate5Module);
        return mapper;
    }
}
于 2020-12-18T19:29:01.620 回答
-1

您可以使用 Gson 而不是 ObjectMapper 并在定义实体时将字段标记为“瞬态”

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 **transient** List<Genre> genre;

}

使用 反序列化时gson.toJson(book),Gson 不会反序列化该元素。

于 2020-06-08T18:40:31.863 回答