I am having one-to-many relationship between Order and LineItem entities. I am exposing them as json response from the RestController.
Order:
#Entity
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "orders")
#XmlRootElement
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long orderId;
private String name;
private String email;
private double price;
#OneToMany(mappedBy = "order", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<LineItem> lineItems;
public void addLineItem(LineItem lineItem){
if(this.lineItems == null){
this.lineItems = new HashSet<>();
}
this.lineItems.add(lineItem);
lineItem.setOrder(this);
}
}
LineItem:
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Getter
#Entity
#ToString(exclude = "order")
#EqualsAndHashCode(exclude = "order")
public class LineItem {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private int qty;
private String name;
private double price;
#ManyToOne
#JoinColumn(name="order_id", nullable = false)
#JsonIgnore
private Order order;
}
The below is my Confiuguration class
#Configuration
public class ApplicationWebConfiguration extends WebMvcConfigurerAdapter {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
//set path extension to true
configurer.favorPathExtension(false).
//set favor parameter to false
favorParameter(true).
parameterName("mediaType").
//ignore the accept headers
ignoreAcceptHeader(true).
//dont use Java Activation Framework since we are manually specifying the mediatypes required below
useJaf(false).
defaultContentType(MediaType.APPLICATION_JSON).
mediaType("xml", MediaType.APPLICATION_XML).
mediaType("json", MediaType.APPLICATION_JSON);
}
}
When I am invoking the request from the browser http://localhost:8222/api/v1/orders?mediaType=xml, I am getting the below error:
Resolved [org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class java.util.ImmutableCollections$SetN] with preset Content-Type 'null']
2022-03-21 22:58:57.511 WARN 153436 --- [nio-8222-exec-1] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation]
2022-03-21 22:58:59.931 WARN 153436 --- [nio-8222-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class java.util.ImmutableCollections$SetN] with preset Content-Type 'null']
2022-03-21 22:58:59.933 WARN 153436 --- [nio-8222-exec-3] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation]
I have added the below dependency as well in the pom.xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.1</version>
</dependency>
Where am I going wrong?
Related
I think i miss misunderstood how bidirectional relation works in JPA.
Club Enitity:
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Setter
#Entity
#Table(name = "club")
public class Club {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#Column(name = "club_name")
private String clubName;
#OneToMany(mappedBy = "club", orphanRemoval = true)
private List<Player> players = new ArrayList<>();
}
Player Entity:
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Setter
#Entity
#Table(name = "player")
public class Player {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#Column(name = "player_name")
private String playerName;
#ManyToOne(optional = false)
#JoinColumn(name = "club_id", nullable = false)
private Club club;
}
One club may have several players, several players can be in one club. Next i create repositiories for for these entities
public interface ClubRepository extends JpaRepository<Club, Long> {}
public interface PlayerRepository extends JpaRepository<Player, Long> { }
and controlers.
#RestController
#RequestMapping("/api/club")
public class ClubController {
#Autowired
ClubRepository clubRepository;
#GetMapping
public List<Club> getALlClubs(){
return clubRepository.findAll();
}
}
#RestController
#RequestMapping("/api/player")
public class PlayerController {
#Autowired
PlayerRepository playerRepository;
#GetMapping
public List<Player> getALlPlayers(){
return playerRepository.findAll();
}
}
I added some data to these tables, but when i call api i have error:
ERROR 11128 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError);
I want to my data in endpoint looks like:
[
"id": 1
"clubName": "madrid"
"players": {
"id": 1
"player_name": "kaka"
}
]
Or something like that, i just want to be able to easily refer to particular data on the frontend side. How should I do it correctly?
my auditing works pretty nice but need to change create listener in that way to obtain null values in first update.
#MappedSuperclass
#Getter
#Setter
#ToString
#EntityListeners(AuditingEntityListener.class)
public abstract class AbstractEntity{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Version
private int version;
#CreatedBy
private String createdBy;
#LastModifiedBy
private String updatedBy;
#CreatedDate
private LocalDateTime createdAt;
#LastModifiedDate
private LocalDateTime updatedAt;
}
#Entity
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Setter
#ToString
public class TestProfile extends AbstractEntity{
private String username;
}
Right now during create entity, the "updatedBy" and "updatedAt" is also fullfilled with duplicated values from "createdBy" and "createdAt". Should I change my default implementation to #PrePersist and #PreUpdate?
Here is my JpaConfig
#Configuration
#EnableJpaAuditing(auditorAwareRef = "auditorAware")
public class AuditingConfig`enter code here` {
#Bean
public AuditorAware<String> auditorAware() {
return () -> Optional.of(((UserDetails) SecurityContextHolder
.getContext().getAuthentication().getPrincipal()).getUsername());
}
}
I have the following entity classes:
#Embeddable
#Getter
#Setter
public class OrganizationCyclePlageKey implements Serializable {
#Column(name = "organization_id")
Long organizationId;
#Column(name = "cycle_plages_id")
Long cyclePlagesId;
...
equals() and hashCode() methods come here
#Entity
#Table(name = "organization_cycle_plages")
#Getter
#Setter
public class OrganizationCyclePlage {
#EmbeddedId
private OrganizationCyclePlageKey id;
#ManyToOne
#MapsId("organizationId")
#JoinColumn(name = "organization_id")
Organization organization;
#ManyToOne
#MapsId("cyclePlagesId")
#JoinColumn(name = "cycle_plages_id")
CyclePlage cyclePlage;
...
other attributes
}
#Entity
#Getter
#Setter
public class CyclePlage extends AbstractEntity {
#OneToMany(mappedBy = "cyclePlage")
private Set<OrganizationCyclePlage> organizationCyclePlages;
...
}
#Entity
#DynamicUpdate
#Getter
#Setter
public class Organization extends AbstractEntity {
#OneToMany(mappedBy = "organization")
private Set<OrganizationCyclePlage> organizationCyclePlages = new HashSet<>();
...
}
SpringBoot app starts up normally without errors.
But when I try to save an instance of OrganizationCyclePlage:
OrganizationCyclePlage ocp = new OrganizationCyclePlage();
ocp.setOrganization(organization);
ocp.setCyclePlage(cyclePlage);
organizationCyclePlageRepository.save(ocp);
it raises the error when calling organizationCyclePlageRepository.save(ocp):
org.hibernate.PropertyAccessException: Could not set field value [361] value by reflection : [class com.XXXX.OrganizationCyclePlageKey.cyclePlagesId] setter of com.XXXX.OrganizationCyclePlageKey.cyclePlagesId
What's wrong with these relations?
I had to add the constructor into the OrganizationCyclePlageKey class to init the foreign keys values as well a default constructor via #NoArgsConstructor annotation:
public OrganizationCyclePlageKey(Long organizationId, Long cyclePlagesId) {
this.organizationId = organizationId;
this.cyclePlagesId = cyclePlagesId;
}
and init the OrganizationCyclePlageKey instance in the OrganizationCyclePlage class:
public class OrganizationCyclePlage {
private OrganizationCyclePlageKey id = new OrganizationCyclePlageKey();
...
}
Domain Classes
#Data
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "SAMPLE_DATA")
#TypeDefs({
#TypeDef(name = "json", typeClass = JsonStringType.class),
#TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
})
public class Sample implements Serializable {
private static final long serialVersionUID = 1719868663566734198L;
#Id
private Long Id;
#Type(type = "json")
#Column(columnDefinition = "json",name = "person")
private Person personObj;
private String sampledata;
private String createdBy;
}
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Person implements Serializable {
private static final long serialVersionUID = -5427425033242474312L;
private String firstName;
private String lastName;
}
Repository Class
#Repository
public interface SampleRepository extends JpaRepository<Sample, Long> {
#Query(value = "select s.personObj,s.sampledata from Sample s where s.Id=:Id")
List<Sample> findPersonById(Long Id);
}
To map to map JSON object types i m using
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>${hibernate-types.version}</version>
</dependency>
when I am trying to fetch the list of Sample object I am getting the following exception
org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.Object[]] to type [#org.springframework.data.jpa.repository.Query com.domain.Sample] for value '[Person(firstName=abc, lastName=test)]'; nested exception is org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [com.domain.Person] to type [#org.springframework.data.jpa.repository.Query com.domain.Sample]
.........
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [com.domain.Person] to type [#org.springframework.data.jpa.repository.Query com.domain.Sample]
You don't have to select the distinct columns. You must select the Entity:
#Repository
public interface SampleRepository extends JpaRepository<Sample, Long> {
#Query(value = "select s from Sample s where s.Id=:Id")
List<Sample> findPersonById(Long Id);
}
I have a simple problem - but I think "I am standing on the tube".
I have a spring boot rest api with JPA, Modelmapper, Entities and DTOs.
But the mapping doesn't work.
Entities:
#Getter
#Setter
#MappedSuperclass
public class AbstractEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
#Getter
#Setter
#Entity(name = "contacts")
public class Contact extends AbstractEntity {
#NotBlank
private String firstName;
#NotBlank
private String lastName;
#Valid
#OneToMany(mappedBy = "contact", cascade = CascadeType.ALL, orphanRemoval = true)
private List<PhoneNumber> phoneNumberList;
}
#Getter
#Setter
#Entity(name = "phone_numbers")
public class PhoneNumber extends AbstractEntity {
#NotBlank
private String label;
#NotBlank
private String number;
#ManyToOne
#JoinColumn(name = "contact_id", referencedColumnName = "id")
#Setter(value = AccessLevel.NONE)
private Contact contact;
}
The DTOs:
#Getter
#Setter
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class ContactDTO {
private Long id;
private String firstName;
private String lastName;
List<PhoneNumberDTO> phoneNumberDTOList = new ArrayList<>();
}
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class PhoneNumberDTO {
private Long id;
private String label;
private String number;
}
My ModelMapperConfig:
#Bean
public ModelMapper modelMapper() {
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration()
.setFieldMatchingEnabled(true)
.setFieldAccessLevel(AccessLevel.PRIVATE);
return modelMapper;
}
Repo:
public interface ContactRepository extends JpaRepository<Contact, Long{
}
Service (only the create method):
#Override
public ContactDTO createOne(ContactDTO contactDTO) {
Contact contact = modelMapper.map(contactDTO, Contact.class);
contactRepository.save(contact);
return contactDTO;
}
Is this the correct way to persist the Contact with its multiple phonenumbers?
And how can I create a simple mapping?
If i want to persist it, there comes an error:
Column 'contact_id' cannot be null