I'm using Springboot and Gson for my backend.
I have these two classes in a many to many relation:
Order class
#Getter
#Setter
#Builder
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table( name = "orders")
public class Order {
#Id
#Expose
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Expose
#NotBlank
private String poNumber;
#Expose
#NotBlank
private String dimension;
#Expose
#NotBlank
private int initialQuantity;
#Expose
#NotBlank
private int leftQuantity;
#Expose
#NotBlank
private Date startDate;
#Expose
#NotBlank
private Date endDate;
#Expose
#SerializedName("status")
#Enumerated(EnumType.STRING)
#Column(length = 20)
private PoStatus status;
#OneToMany(mappedBy="order")
private Set<Log> logs;
#Expose
#SerializedName("products")
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable( name = "orders_products",
joinColumns = #JoinColumn(name = "order_id"),
inverseJoinColumns = #JoinColumn(name = "sap_code"))
private Set<Product> products = new HashSet<>();
Product Class
#Getter
#Setter
#Builder
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table( name = "products")
public class Product {
#Expose
#Id
#NotBlank
private String sapCode;
#Expose
#NotBlank
private String sapCodeDescription;
#Expose
private String productData;
}
And this is the service that I use to serve the data to my rest endpoint
public String getAllOrders() {
List<Order> allOrders = orderRepository.findAll();
String allOrdersResult = gson.toJson(allOrders);
return allOrdersResult;
}
And this is the response:
[
{
"id": 1,
"poNumber": "003100059361",
"dimension": "INTBKGR",
"initialQuantity": 200000,
"leftQuantity": 200000,
"startDate": "17/08/2022 00:00",
"endDate": "17/08/2022 00:00",
"status": "READY",
"products": [
{
"sapCode": "000000000000416234",
"sapCodeDescription": "1.STUFE 15X",
"productData": "{\"pieces\": 85, \"mark\": true, \"description\": \"elementum pellentesque quisque porta volutpat erat quisque erat eros viverra eget congue eget\"}"
}
]
}
]
My aim is to deserialize/escape the productData String property.
I've tried by creating a ProductData class and using the #JsonAdapter annotation, but as far as I understood this annotation Is used when you need to give a custom behaviour to your deserialization, the JSON string in my example is very simple and I don't need any particular logic behind it.
I think you have to declare a class for that and change productData type from string to that class.
I resolved in this way, I think this is NOT a good approach and I hope that there is a more automatic approach to solve this.
Product Class
public class Product {
#Expose
#Id
#NotBlank
private String sapCode;
#Expose
#NotBlank
private String sapCodeDescription;
//THIS PROPERTY IS TO SAVE THE JSON IN THE DB
#NotBlank
#Column(columnDefinition="TEXT")
#JsonProperty
private String productDataColumn;
//THIS PROPERTY IS TO EXPOSE THE DATA TO THE API
#Transient
#Expose
private ProductData productData;
public void createProductData() {
this.productData = new Gson().fromJson(productDataColumn, ProductData.class);
}
}
ProductData Class
public class ProductData {
#Expose
public int pieces;
#Expose
public boolean marcatura;
#Expose
public String description;
}
OrderService
public String getAllOrders() {
List<Order> allOrders = orderRepository.findAll();
for(Order o : allOrders){
Product orderProduct = o.getProducts().stream().findFirst().get();
orderProduct.createProductData();
}
String allOrdersResult = gson.toJson(allOrders);
return allOrdersResult;
}
Related
I have two entities Account and Order where one account can have one or more orders. I want to be able to log into an Account and then have order(s) for that account. Whenever I post an order for an existing account everything gets filled in properly but "account_id"(the foreign key). I would like to know why "account_id" is null and what I can do to address this problem, thanks.
Here is the Account entity:
#Entity
#Table(name="account")
public class Account {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private long id;
#Column(name="first_name")
private String firstName;
#Column(name="last_name")
private String lastName;
#Column(name="email")
private String email;
#Column(name="user_name")
private String userName;
#Column(name="password")
private String password;
#Column(name="address")
private String address;
#Column(name="city")
private String city;
#Column(name="state")
private String state;
#Column(name="country")
private String country;
#Column(name="zipcode")
private String zipcode;
#Column(name="credit_card_number")
private String creditCardNumber;
#Column(name="credit_card_code")
private int creditCardCode;
#Column(name="credit_card_name")
private String creditCardName;
#Column(name="credit_card_expiration_month")
private int creditCardExpirationMonth;
#Column(name="credit_card_expiration_year")
private int creditCardExpirationYear;
#OneToMany(mappedBy = "account", cascade = CascadeType.ALL)
private List<Order> orders;
/* constructor */
/* Getters and setters */
Here is the Order entity:
#Entity
#Table(name="orders")
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private long id;
#Column(name="total_price")
private int totalPrice;
#Column(name="total_quantity")
private int totalQuantity;
#Column(name="date_created")
#CreationTimestamp
private Date dateCreated;
#Column(name="shipping_address")
private String shippingAddress;
#ManyToOne
#JoinColumn(name = "account_id",nullable = false, insertable = false, updatable = false)
private Account account;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "order")
private Set<OrderItem> orderItems = new HashSet<>();
/* constructor */
/* Getters and setters */
Here is the Order Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
Page<Order> findByAccountId(#Param("id") Long id, Pageable pageable);
}
Here is the Order Controller
#RestController
#RequestMapping("/api")
public class OrderController {
#Autowired
private OrderRepository orderRepository;
#PostMapping("/save-order")
public Order saveOrder(#RequestBody Order order) {
return orderRepository.save(order);
}
}
Here is the postman post for order
URL: "http://localhost:8080/api/save-order"
{
"totalPrice": 10.17,
"totalQuantity": 3,
"dateCreated": "2022-09-05",
"shippingAddress": "123 Road, London, United Kingdom",
"account": [{
"id": 1,
"firstName": "Winston",
"lastName": "Smith",
"email": "smith22#gmail.com",
"userName": "wilsonsmith22",
"password": "mypassword22",
"address": "123 Road",
"city": "London",
"state": "London Region",
"country": "United Kingdom",
"zipcode": "220220",
"creditCardNumber": "4422336644885500",
"creditCardCode": 234,
"creditCardName": "Winston Smith",
"creditCardExpirationMonth": 5,
"creditCardExpirationYear": 2025
}]
}
You have :
#ManyToOne
#JoinColumn(name = "account_id",nullable = false, insertable = false, updatable = false)
private Account account;
#Column(name = "account_id")
private long accountId;
Both fields account & accountId have the same name, which souldn't happen I guess.
my Entity is:
#Data
#Entity
#Table(name = "CORE_BOOK")
public class Book extends BaseEntity<Integer>{
#Column(name = "TITLE")
private String title;
#Column(name = "AUTHOR")
private String author;
#Column(name = "ISBN_NUMBER")
private String isbnNumber;
#Column(name = "price")
private Long price;
#Column(name = "LANGUAGE")
private String language;
#Column(name = "COVER_PHOTO_URL")
private String coverPhotoUrl;
}
and BaseEntity
#MappedSuperclass
public class BaseEntity<T extends Serializable> implements Serializable {
private static final long serialVersionUID = 95231478632145632L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private T id;
}
then when i breakpoint on findAll in controller i can see id in array List
#GetMapping("/list")
#ResponseBody
public List<Book> findAll() {
return bookRepository.findAll();
}
but in generated-request.http or in frontend (react table) , extended property (id) doesn't load
GET http://localhost:8080/rest/books/list
and the result as follows:
{
"title": "test",
"author": "SMH",
"isbnNumber": "513548",
"price": 150000,
"language": "English",
"coverPhotoUrl": "../images.jpg"
}
please help me how i can see extended property in frontend
I have two Entities in my spring boot application. I am working with dtos and displaying my dto in the end. But I am getting the wrong output from my getRequest. My first entity is MeetingSetting which can have multiple MeetingTimes and inside MeetingTime I have meetingName as a foreign key. I want to display meetingTime like this:
{
"id": 1,
"date": "2021-06-31",
"startTime": "15:30",
"endTime": "16:30",
"meetingName": "Test"
}
But I am getting instead this one:
{
"id": 1,
"date": "2021-06-31",
"startTime": "15:30",
"endTime": "16:30",
"meetingName": {
"id": 1,
"meetingName": "Tewasddweewrst2",
"meetingUrl": null,
"meetingPw": ""
}
}
Could someone take a look at my code and tell me what I am doing wrong?
MeetingSetting Entity::
#Entity
#Table(name = "meeting_settings")
#Setter
#Getter
public class MeetingsSetting implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "meeting_name", unique = true)
private String meetingName;
#Column(name = "meeting_url")
private String meetingUrl;
#Column(name = "meeting_pw")
private String meetingPw;
#OneToMany(mappedBy = "meetingName", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<MeetingTime> meetingTime = new HashSet<>();
}
MeetingSettingDTO:
#Getter
#Setter
public class MeetingSettingDTO {
private Long id;
#NotNull
private String meetingName;
#NotNull
private String meetingUrl;
#NotNull
private String meetingPw;
#JsonIgnore
private Set<MeetingTime> meetingTime;
}
MeetingTimeEntity:
#Entity
#Table(name = "meeting_times")
#Getter
#Setter
public class MeetingTime implements Serializable {
#JsonIgnore
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "meeting_date")
private String date;
#Column(name = "start_time")
private String startTime;
#Column(name = "end_time")
private String endTime;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "meeting_name" , referencedColumnName = "meeting_name")
private MeetingsSetting meetingName;
}
MeetingTimeDTO:
#Getter
#Setter
public class MeetingTimeDTO {
private Long id;
#NotNull
private String date;
#NotNull
private String startTime;
#NotNull
private String endTime;
private MeetingSettingDTO meetingName;
}
In my service I am first getting MeetingTime as an entity from my repository then converting it to DTO and returning it for my controller:
#Service
public class MeetingTimeService {
ModelMapper modelMapper = new ModelMapper();
#Autowired
MeetingTimeRepository meetingTimeRepository;
public List<MeetingTimeDTO> findAllMeetingTimes(){
List<MeetingTime> meetingTimeList = meetingTimeRepository.findAll();
return meetingTimeList.stream()
.map(this::convertToDto)
.collect(Collectors.toList());
}
private MeetingTimeDTO convertToDto(MeetingTime meetingTime) {
MeetingTimeDTO meetingTimeDTO = modelMapper.map(meetingTime, MeetingTimeDTO.class);
return meetingTimeDTO;
}
}
Controller:
#GetMapping(value = "/" )
public List<MeetingTimeDTO> getAllTimes() {
return meetingTimeService.findAllMeetingTimes();
}
In MeetingTimeDTO:
private MeetingSettingDTO meetingName;
The type needs to be changed to:
private string meetingName;
I have not worked with ModelMapper so cannot help you with how to map a specific field from the related object but this answer here seems to provide the info needed.
I am currently trying to perform an Entity to DTO mapping using ModelMapper's map method. On the deepest property mapping, the mapping result is null but it should be an object.
These are my mapping source Entities(Omitting Loombok Getters and Setters for brevety):
public class Client implements Serializable
{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
public Long id;
#NotEmpty
public String name;
#NotEmpty
public String surname;
#NotEmpty
#Email
public String email;
#Column(name="creation_date", updatable=false)
#Temporal(TemporalType.DATE)
#DateTimeFormat(pattern="yyyy-MM-dd")
public Date creationDate;
public String photo;
#OneToMany(mappedBy="client", fetch=FetchType.LAZY, cascade=CascadeType.ALL, orphanRemoval=true)
public List<Invoice> invoices;
}
public class Invoice implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Long id;
#NotEmpty
public String description;
public String comment;
#Temporal(TemporalType.DATE)
#Column(name = "creation_date", updatable = false)
#DateTimeFormat(pattern = "yyyy-MM-dd")
public Date creationDate;
#ManyToOne(fetch = FetchType.LAZY)
public Client client;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "invoice_id")
public List<InvoiceItem> items;
}
public class InvoiceItem implements Serializable
{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
public Long id;
public Integer amount;
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name="product_id")
public Product product;
}
public class Product implements Serializable
{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
public Long id;
public String name;
public Double prize;
#Temporal(TemporalType.DATE)
#Column(name="creation_date", updatable=false)
#DateTimeFormat(pattern="yyyy-MM-dd")
public Date creationDate;
}
And these are my target DTOs(Omitting Loombok Getters and Setters for brevety):
public class ClientDTO implements Serializable
{
#JsonIgnore
public Long id;
public String name;
public String surname;
public String email;
#JsonIgnore
public Date creationDate;
public String photo;
}
public class ClientWithInvoicesDTO extends ClientDTO implements Serializable
{
#JsonManagedReference
public List<InvoiceDTO> invoices;
}
public class InvoiceDTO implements Serializable
{
#JsonIgnore
public Long id;
public String description;
public String comment;
public Date creationDate;
#JsonBackReference
public ClientDTO client;
public List<InvoiceItemDTO> items;
}
public class InvoiceItemDTO implements Serializable
{
#JsonIgnore
public Long id;
public Integer amount;
public ProductDTO productDTO;
}
public class ProductDTO implements Serializable
{
#JsonIgnore
public Long id;
public String name;
public Double prize;
#JsonIgnore
public Date creationDate;
}
And on my Controller class method I am doing mapping like this:
#RequestMapping(value = "/{id}/with-invoices", method = RequestMethod.GET)
public ResponseEntity findOneWithInvoices(#PathVariable Long id)
{
Client wantedClient = this.clientService.findOneWithInvoices(id);
ClientWithInvoicesDTO wantedClientWithInvoicesDto = this.modelMapper.map(wantedClient, ClientWithInvoicesDTO.class);
return new ResponseEntity<>(wantedClientWithInvoicesDto, HttpStatus.OK);
}
My clientService is correctly returning the data but "product" property is null on JSON response and it shouldn't be:
{
"name": "cupiditate",
"surname": "veritatis",
"email": "george.prohaska#example.com",
"photo": "ec0327a5-3de8-328c-a812-9000d6d5507d",
"invoices": [
{
"description": "Distinctio autem id vel necessitatibus unde omnis rerum. Minus maxime quos doloribus. Voluptatem amet praesentium sit magni quia molestiae. Officia aspernatur numquam ut perspiciatis a.",
"comment": "Odio enim libero tempore molestiae.",
"creationDate": "2013-02-16",
"items": [
{
"amount": 6,
"productDTO": null
},
...
Can anyone help me with this?
Shouldn't you put #Entity before your class? Like that:
#Entity
public class MyClass {
...
}
As M. Deinum says on comment below, on InvoiceItemDTO product property should be named as "product" instead of "productDTO". Now it works fine
Find below entity classes :
#Entity
#Table(name="rooms")
public class RoomEntity {
#Column(name="mr_code", length=50, nullable=false)
private String code;
#Column(name="mr_roomtype", nullable=false, length=50)
private String type;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "mr__hotelId", nullable = false)
private HotelEntity hotel;
//getters and setters
}
#Entity
#Table(name="hotels")
public class HotelEntity{
#Column(name="mh_name", nullable=false)
private String name;
#Column(name="mh_description")
private String description;
#OneToMany(mappedBy = "hotel", fetch=FetchType.EAGER)
private Set<RoomEntity> rooms = new HashSet<>(0);
//getters and setters
}
Find below DTO class
public class RoomDTO{
private String hotelName;
private String code;
private String type;
//getters and setters
}
I written the below mapper code to copy data from RoomEntity to RoomDTO
public class BeanMapper {
private static MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
public static RoomDTO toRoomDTO(RoomEntity roomEntity) {
mapperFactory.classMap(RoomEntity.class, RoomDTO.class).field("hotel.name","hotelName").byDefault().register();
MapperFacade mapper = mapperFactory.getMapperFacade();
return mapper.map(roomEntity,RoomDTO.class);
}
}
The properties - code and type values are getting copied from RoomEntity to RoomDTO.
But the nested properties values(hotel.name -> hotelName) are not getting copied.
Please help to resolve this issue.