Java Spring boot @ResponseBody 不序列化实体 id

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24839760/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 15:06:30  来源:igfitidea点击:

Spring boot @ResponseBody doesn't serialize entity id

javajsonspringspring-boot

提问by Konstantin

Have a strange problem and can't figure out how to deal with it. Have simple POJO:

遇到一个奇怪的问题,不知道如何处理。有简单的POJO:

@Entity
@Table(name = "persons")
public class Person {

    @Id
    @GeneratedValue
    private Long id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "middle_name")
    private String middleName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "comment")
    private String comment;

    @Column(name = "created")
    private Date created;

    @Column(name = "updated")
    private Date updated;

    @PrePersist
    protected void onCreate() {
        created = new Date();
    }

    @PreUpdate
    protected void onUpdate() {
        updated = new Date();
    }

    @Valid
    @OrderBy("id")
    @OneToMany(mappedBy = "person", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<PhoneNumber> phoneNumbers = new ArrayList<>();

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getMiddleName() {
        return middleName;
    }

    public void setMiddleName(String middleName) {
        this.middleName = middleName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    public Date getCreated() {
        return created;
    }

    public Date getUpdated() {
        return updated;
    }

    public List<PhoneNumber> getPhoneNumbers() {
        return phoneNumbers;
    }

    public void addPhoneNumber(PhoneNumber number) {
        number.setPerson(this);
        phoneNumbers.add(number);
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
    }
}

@Entity
@Table(name = "phone_numbers")
public class PhoneNumber {

    public PhoneNumber() {}

    public PhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    @Id
    @GeneratedValue
    private Long id;

    @Column(name = "phone_number")
    private String phoneNumber;

    @ManyToOne
    @JoinColumn(name = "person_id")
    private Person person;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
    }
}

and rest endpoint:

和休息端点:

@ResponseBody
@RequestMapping(method = RequestMethod.GET)
public List<Person> listPersons() {
    return personService.findAll();
}

In json response there are all fields except Id, which I need on front end side to edit/delete person. How can I configure spring boot to serialize Id as well?

在 json 响应中有除 Id 之外的所有字段,我需要在前端编辑/删除人员。如何配置 spring boot 以序列化 Id?

That's how response looks like now:

这就是现在的响应:

[{
  "firstName": "Just",
  "middleName": "Test",
  "lastName": "Name",
  "comment": "Just a comment",
  "created": 1405774380410,
  "updated": null,
  "phoneNumbers": [{
    "phoneNumber": "74575754757"
  }, {
    "phoneNumber": "575757547"
  }, {
    "phoneNumber": "57547547547"
  }]
}]

UPD Have bidirectional hibernate mapping, maybe it's somehow related to issue.

UPD 有双向休眠映射,也许它与问题有某种关系。

采纳答案by Patrick Grimard

I recently had the same problem and it's because that's how spring-boot-starter-data-restworks by default. See my SO question -> While using Spring Data Rest after migrating an app to Spring Boot, I have observed that entity properties with @Id are no longer marshalled to JSON

我最近遇到了同样的问题,因为这是spring-boot-starter-data-rest默认情况下的工作方式。请参阅我的 SO 问题 ->在将应用程序迁移到 Spring Boot 后使用 Spring Data Rest 时,我观察到带有 @Id 的实体属性不再编组为 JSON

To customize how it behaves, you can extend RepositoryRestConfigurerAdapterto expose IDs for specific classes.

要自定义其行为方式,您可以扩展RepositoryRestConfigurerAdapter以公开特定类的 ID。

import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;

@Configuration
public class RepositoryConfig extends RepositoryRestConfigurerAdapter {
    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        config.exposeIdsFor(Person.class);
    }
}

回答by Konstantin

Hm, ok seems like I found the solution. Removing spring-boot-starter-data-rest from pom file and adding @JsonManagedReference to phoneNumbers and @JsonBackReference to person gives desired output. Json in response isn't pretty printed any more but now it has Id. Don't know what magic spring boot performs under hood with this dependency but I don't like it :)

嗯,好吧似乎我找到了解决方案。从 pom 文件中删除 spring-boot-starter-data-rest 并将 @JsonManagedReference 添加到 phoneNumbers 并将 @JsonBackReference 添加到 person 提供所需的输出。响应的 Json 不再打印出来,但现在它有 Id。不知道具有这种依赖性的神奇弹簧靴在引擎盖下执行了什么,但我不喜欢它:)

回答by eric peladan

With Spring Boot you have to extends SpringBootRepositoryRestMvcConfiguration
if you use RepositoryRestMvcConfigurationthe configuration define in application.properties may not worked

使用 Spring Boot 你必须扩展SpringBootRepositoryRestMvcConfiguration
如果你使用RepositoryRestMvcConfiguration在 application.properties 中定义的配置可能不起作用

@Configuration
public class MyConfiguration extends SpringBootRepositoryRestMvcConfiguration  {

@Override
protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
    config.exposeIdsFor(Project.class);
}
}

But for a temporary need You can use projection to include idin the serialization like :

但是对于临时需要,您可以使用投影在序列化中包含id,例如:

@Projection(name = "allparam", types = { Person.class })
public interface ProjectionPerson {
Integer getIdPerson();
String getFirstName();
String getLastName();

}

}

回答by Salvatorelab

Answer from @eric-peladan didn't work out of the box, but was pretty close, maybe that worked for previous versions of Spring Boot. Now this is how it is supposed to be configured instead, correct me if I'm wrong:

来自@eric-peladan 的回答不是开箱即用的,但非常接近,也许这适用于以前版本的 Spring Boot。现在这就是它应该如何配置,如果我错了,请纠正我:

import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;

@Configuration
public class RepositoryConfiguration extends RepositoryRestConfigurerAdapter {

    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        config.exposeIdsFor(User.class);
        config.exposeIdsFor(Comment.class);
    }
}

回答by Андрей Миронов

Easy way: rename your variable private Long id;to private Long Id;

简单方法:将变量重命名private Long id;private Long Id;

Works for me. You can read more about it here

为我工作。你可以在这里阅读更多关于它的信息

回答by lcnicolau

In case you need to expose the identifiers for all entities:

如果您需要公开所有实体的标识符:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer;

import javax.persistence.EntityManager;
import javax.persistence.metamodel.Type;

@Configuration
public class RestConfiguration implements RepositoryRestConfigurer {

    @Autowired
    private EntityManager entityManager;

    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        config.exposeIdsFor(
                entityManager.getMetamodel().getEntities().stream()
                .map(Type::getJavaType)
                .toArray(Class[]::new));
    }
}

Note that in versions of Spring Boot prior to 2.1.0.RELEASEyou must extend the (now deprecated)org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapterinstead of implement RepositoryRestConfigurerdirectly.

请注意,在之前的 Spring Boot 版本中,2.1.0.RELEASE您必须扩展(现已弃用)org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter而不是RepositoryRestConfigurer直接实现。



If you only want to expose the identifiers of entities that extends or implements specific super class or interface:

如果您只想公开扩展或实现特定超类或接口的实体的标识符:

    ...
    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        config.exposeIdsFor(
                entityManager.getMetamodel().getEntities().stream()
                .map(Type::getJavaType)
                .filter(Identifiable.class::isAssignableFrom)
                .toArray(Class[]::new));
    }


If you only want to expose the identifiers of entities with a specific annotation:

如果您只想公开具有特定注释的实体标识符:

    ...
    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        config.exposeIdsFor(
                entityManager.getMetamodel().getEntities().stream()
                .map(Type::getJavaType)
                .filter(c -> c.isAnnotationPresent(ExposeId.class))
                .toArray(Class[]::new));
    }

Sample annotation:

示例注释:

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExposeId {}

回答by David B.

@Component
public class EntityExposingIdConfiguration extends RepositoryRestConfigurerAdapter {

    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        try {
            Field exposeIdsFor = RepositoryRestConfiguration.class.getDeclaredField("exposeIdsFor");
            exposeIdsFor.setAccessible(true);
            ReflectionUtils.setField(exposeIdsFor, config, new ListAlwaysContains());
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

    class ListAlwaysContains extends ArrayList {

        @Override
        public boolean contains(Object o) {
            return true;
        }
    }
}

回答by Gisomar Junior

The class RepositoryRestConfigurerAdapterhas been deprecated since 3.1, implement RepositoryRestConfigurerdirectly.

该类RepositoryRestConfigurerAdapter自 3.1 起已弃用,RepositoryRestConfigurer直接实现。

@Configuration
public class RepositoryConfiguration implements RepositoryRestConfigurer  {
 @Override
 public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
  config.exposeIdsFor(YouClass.class);
  RepositoryRestConfigurer.super.configureRepositoryRestConfiguration(config);
 }
}

Font: https://docs.spring.io/spring-data/rest/docs/current-SNAPSHOT/api/org/springframework/data/rest/webmvc/config/RepositoryRestConfigurer.html

字体:https: //docs.spring.io/spring-data/rest/docs/current-SNAPSHOT/api/org/springframework/data/rest/webmvc/config/RepositoryRestConfigurer.html