java - requestbody - spring mvc responsebody example
Spring boot @ResponseBody no serializa la identidad de la entidad (6)
Tiene un problema extraño y no puede entender cómo lidiar con él. Tener POJO simple:
@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);
}
}
y punto final de descanso:
@ResponseBody
@RequestMapping(method = RequestMethod.GET)
public List<Person> listPersons() {
return personService.findAll();
}
En la respuesta json hay todos los campos, excepto Id, que necesito en el anverso para editar / eliminar persona. ¿Cómo puedo configurar el arranque de resorte para serializar Id también?
Así es como se ve la respuesta ahora:
[{
"firstName": "Just",
"middleName": "Test",
"lastName": "Name",
"comment": "Just a comment",
"created": 1405774380410,
"updated": null,
"phoneNumbers": [{
"phoneNumber": "74575754757"
}, {
"phoneNumber": "575757547"
}, {
"phoneNumber": "57547547547"
}]
}]
UPD Tiene un mapa de hibernación bidireccional, tal vez esté relacionado de alguna manera con el problema.
En caso de que necesite exponer los identificadores para todas las entidades :
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.RepositoryRestConfigurerAdapter;
import javax.persistence.EntityManager;
import javax.persistence.metamodel.Type;
@Configuration
public class RestConfiguration extends RepositoryRestConfigurerAdapter {
@Autowired
private EntityManager entityManager;
@Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(
entityManager.getMetamodel().getEntities().stream()
.map(Type::getJavaType)
.toArray(Class[]::new));
}
}
Si solo desea exponer los identificadores de las entidades que amplían o implementan una súper clase o interfaz específica :
...
@Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(
entityManager.getMetamodel().getEntities().stream()
.map(Type::getJavaType)
.filter(Identifiable.class::isAssignableFrom)
.toArray(Class[]::new));
}
Si solo desea exponer los identificadores de las entidades con una anotación específica :
...
@Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(
entityManager.getMetamodel().getEntities().stream()
.map(Type::getJavaType)
.filter(c -> c.isAnnotationPresent(ExposeId.class))
.toArray(Class[]::new));
}
Anotación de muestra:
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExposeId {}
Con Spring Boot tienes que extender SpringBootRepositoryRestMvcConfiguration
si usa RepositoryRestMvcConfiguration, la configuración definida en application.properties puede no funcionar
@Configuration
public class MyConfiguration extends SpringBootRepositoryRestMvcConfiguration {
@Override
protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(Project.class);
}
}
Pero para una necesidad temporal, puede usar la proyección para incluir el ID en la serialización como:
@Projection(name = "allparam", types = { Person.class })
public interface ProjectionPerson {
Integer getIdPerson();
String getFirstName();
String getLastName();
}
Hace poco tuve el mismo problema y es porque así es como funciona spring-boot-starter-data-rest
de manera predeterminada. Vea mi pregunta sobre SO -> Mientras uso Spring Data Rest después de migrar una aplicación a Spring Boot, he observado que las propiedades de la entidad con @Id ya no están organizadas para JSON
Para personalizar cómo se comporta, puede extender RepositoryRestConfigurerAdapter
para exponer ID para clases específicas.
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
protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(Person.class);
}
}
Hm, parece que encontré la solución. Eliminando spring-boot-starter-data-rest del archivo pom y agregando @JsonManagedReference a phoneNumbers y @JsonBackReference a person, da el resultado deseado. Json en respuesta ya no está muy bien impreso, pero ahora tiene Id. No sé lo que la bota de muelles mágica realiza debajo de la capucha con esta dependencia, pero no me gusta :)
La respuesta de @ eric-peladan no funcionó de la caja, pero estuvo bastante cerca, tal vez eso funcionó para versiones anteriores de Spring Boot. Ahora así es como se supone que debe configurarse, corrígeme si me equivoco:
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);
}
}
Manera fácil: cambie el nombre de su private Long id;
variable private Long id;
a private Long Id;
Funciona para mi. Puedes leer más sobre esto here