I am learning spring boot. As a part of this learning, I am creating a invoicing application's backend using REST Webservices. Here is my JSON Request.
{
"invoice": {
"invoiceNumber":"KB123456",
"custId":"123",
"pricingId":"234",
"empId":"456",
"gstCode":"HSN1234",
"invoiceSubTotal":"1234.00",
"invoiceGst":"18%",
"invoiceGstAmount":"123.45",
"invoiceTotal":"1357.45",
"invoiceLineItems": [
{
"invoiceLineNo":"KB123456-1",
"invoiceLineDesc":"Des123",
"invoiceQty":"2",
"invoicePpu":"0.18",
"invoiceGstCode":"HSN1235",
"invoiceGstPercentage":"18%",
"invoiceLineAmount":"123",
"invoiceLineTaxAmount":"12",
"invoiceLineTotalAmount":"135"
},
{
"invoiceLineNo":"KB123456-2",
"invoiceLineDesc":"Des124",
"invoiceQty":"4",
"invoicePpu":"0.17",
"invoiceGstCode":"HSN1235",
"invoiceGstPercentage":"18%",
"invoiceLineAmount":"126",
"invoiceLineTaxAmount":"14",
"invoiceLineTotalAmount":"140"
}
]
}
}
invoiceLineItems can house up to 15 objects.
Here are my Entities Invoice and InvoiceLineItems
Invoice.Java
#Entity
public class Invoice {
#Id
#GeneratedValue
private long invoiceId;
private String invoiceNumber;
private long custId;
private long pricingId;
private long empId;
private String gstCode;
private String invoiceSubTotal;
private String invoiceGst;
private String invoiceGstAmount;
private String invoiceTotal;
#Transient
#OneToMany(mappedBy="invoice")
private List<InvoiceLineItems> invoiceLineItems;
}
InvoiceLineItems.Java
#Entity
public class InvoiceLineItems {
#Id
#GeneratedValue
private long invoiceLineId;
private String invoiceNumber;
private String invoiceLineNo;
private String invoiceLineDesc;
private String invoiceQty;
private String invoicePpu;
private String invoiceGstCode;
private String invoiceGstPercentage;
private String invoiceLineAmount;
private String invoiceLineTaxAmount;
private String invoiceLineTotalAmount;
#ManyToOne
private Invoice invoice;
}
Here is my REST Controller
#RestController
public class InvoiceResourceController {
#Autowired
InvoiceRepository invoiceRepository;
InvoiceLineRepository invoiceLineRepository;
#PostMapping("/invoice")
public ResponseEntity<Invoice> createInvoice(#RequestBody Invoice invoice) {
List<InvoiceLineItems> invoiceLineItemsList = invoice.getInvoiceLineItems();
Invoice savedInvoice = invoiceRepository.save(invoice);
/* for (int i = 0; i < invoiceLineItemsList.size(); i++) {
InvoiceLineItems invLn = new InvoiceLineItems();
invLn = invoiceLineItemsList.get(i);
invoiceLineRepository.save(invLn);
} */
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}")
.buildAndExpand(savedInvoice.getInvoiceNumber()).toUri();
return ResponseEntity.created(location).build();
}
}
Now, I have two tables Invoice and Invoice_Line_Items created by Spring Boot. I am able to persist the Invoice Entity to the Invoice table, but I'm struggling to get the InvoiceLineItems Array Object from request and persisting to Invoice_Line_Items table.
Any help will be appreciated.
Solved it.
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "invoiceNumber")
private List<InvoiceLineItems> invoiceLineItems;
Related
In my database I have two tables airport and calendar connected by foreight key airport_id. I want to get json response with data from two tables for the determined airport_id=273
For example I want to get data for Airport with airport_id and Calendar with foreight key airport_id equels 273. Actually, I've got empty response from localhost:8080. I didn't get any error, just a blank page, like on the picture below. What I do wrong? Thank you in advance!
Airport.java
#Entity
#Table(name = "airport")
public class Airport {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer airport_id;
#Column(name = "departureAirport")
private String departureAirport;
#Column(name = "destinationAirport")
private String destinationAirport;
#OneToMany(mappedBy = "airport")
#JsonManagedReference("airport")
private List<Calendar> calendars; ....
Calendar.java
#Entity
#Table(name = "calendar")
public class Calendar {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer calendar_id;
#Column(name = "departureTime")
private Time departureTime;
#Column(name = "destinationTime")
private Time destinationTime;
#ManyToOne(targetEntity = Airport.class)
#JoinColumn(name = "airport_id")
#JsonBackReference("airport")
private Airport airport; ....
CalendarController.java
public class CalendarController {
#Autowired
CalendarService calendarService;
#Autowired
AirportService airportService;
#GetMapping(value = "/search/{airport_id}")
public List<Calendar> getCalendars(#PathVariable("airport_id") Integer airport_id) {
Airport airport = airportService.findOne(airport_id);
return calendarService.findOne(airport);
}}
CalendarRepository.java
public interface CalendarRepository extends CrudRepository<Calendar, Integer> {
Calendar getOne(int calendar_id);
List<Calendar> findByAirport(Airport airport_id);
}
CalendarService.java
public interface CalendarService {
List<Calendar> findOne(Airport airport_id);
}
CalendarServiceImpl.java
#Service
public class CalendarServiceImpl implements CalendarService {
#Autowired
CalendarRepository repository;
#Autowired
AirportRepository airportRepository;
#Override
public List<Calendar> getCalendars(Integer airport_id) {
Airport airport = airportRepository.getOne(airport_id);
return repository.findByAirport(airport);
}}
Update
AirpostService.java
public interface AirportService {
Airport findOne(int airport_id);
}
AirportRepository.java
public interface AirportRepository extends CrudRepository<Airport, Integer> {
Airport getOne(Integer airport_id);
}
The problem is not your Hibernate, but your Controller. You just need to add the #Responsebody annotation to your method. The #ResponseBody annotation tells a controller that the object returned is automatically serialized into JSON.
#GetMapping(value = "/search/{airport_id}")
#ResponseBody
public List<Calendar> getCalendars(#PathVariable("airport_id") Integer airport_id) {
Airport airport = airportService.findOne(airport_id);
return calendarService.findOne(airport);
}}
I found this code snippet while looking at other projects and I was wondering on the benefit of having a public interface within a java pojo. Why should you use it as seen in the below example. Is the below use considered a best practice? Is there a catch with using an interface liek this?
#Data
#NoArgsConstructor
#Entity
#Table(name = "customer_mapping", schema = "billing")
public class CustomerMapping {
public interface createCustomerMapping {
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#JsonProperty("customerMappingId")
private Integer id;
#Column(length=10)
#NotNull(groups = { createCustomerMapping.class })
#NotEmpty(groups = { createCustomerMapping.class })
#Size(groups = { createCustomerMapping.class }, min = 4, max = 4)
private String issuerCode;
#Column(length=10)
#NotNull(groups = { createCustomerMapping.class })
#NotEmpty(groups = { createCustomerMapping.class })
private String offerCode;
#NotNull
private Long customerId;
#CreationTimestamp
private LocalDateTime createdTs;
private String createdBy;
#UpdateTimestamp
private LocalDateTime updatedTs;
private String updatedBy;
public CustomerMapping(String offerCode) {
this.offerCode = offerCode;
}
public CustomerMapping(String issuerCode, String offerCode) {
this.issuerCode = issuerCode;
this.offerCode = offerCode;
}
public CustomerMapping(String issuerCode, String offerCode, Long customerId) {
this.issuerCode = issuerCode;
this.offerCode = offerCode;
this.customerId = customerId;
}
}
From what I know an interface is used to define a contract so I'm familiar with the implementation in using it via a library of code or if two teams needs to co-operate. But in the above example, its unclear to me.
I try select data from the table by a filter with Spring Data JPA Specification I think what my implementation is correct, But it doesn't work. Help me please understand my mistake and fix my example.
I have very strange SQL query in log :
select phone0_.id as id1_0_, phone0_.note as note2_0_, phone0_.number as number3_0_, phone0_.operator_login as operator4_0_, phone0_.operator_pass as operator5_0_, phone0_.operator_name as operator6_0_, phone0_.operator_url as operator7_0_, phone0_.reg_date as reg_date8_0_, phone0_.status as status9_0_ from phone phone0_ where 0=1 limit ?
In the end: where 0=1 it's crash my mind. Where did that come from?
Here I fill CriteriaBuilder if filter field not null. I expect to get correctly built Specification object and send it to findAll(Specifications.where(specification), Pageable p) method. But something incorrect.
My repo and specification impl:
public interface PhoneRepository extends CrudRepository<Phone, Integer>, JpaRepository<Phone, Integer>, JpaSpecificationExecutor<Phone> {
class PhoneSpecification implements Specification<Phone> {
private final #NonNull PhoneService.PhoneFilter filter;
public PhoneSpecification(#NonNull PhoneService.PhoneFilter filter) {
this.filter = filter;
}
#Override
public Predicate toPredicate(Root<Phone> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
Predicate predicate = cb.disjunction();
if (nonNull(filter.getId())) {
cb.disjunction().getExpressions().add(cb.equal(root.get("id"), filter.getId()));
}
if (nonNull(filter.getNote())) {
cb.disjunction().getExpressions().add(cb.like(root.get("note"), filter.getNote()));
}
if (nonNull(filter.getNumber())) {
cb.disjunction().getExpressions().add(cb.like(root.get("number"), filter.getNumber()));
}
if (nonNull(filter.getStatus())) {
cb.disjunction().getExpressions().add(cb.like(root.get("status"), filter.getStatus()));
}
if (nonNull(filter.getOpName())) {
cb.disjunction().getExpressions().add(cb.like(root.get("operatorName"), filter.getOpName()));
}
if (nonNull(filter.getOpLogin())) {
cb.disjunction().getExpressions().add(cb.like(root.get("operatorAccLogin"), filter.getOpLogin()));
}
if (nonNull(filter.getOpPassword())) {
cb.disjunction().getExpressions().add(cb.like(root.get("operatorAccPassword"), filter.getOpPassword()));
}
if (nonNull(filter.getRegFrom()) && nonNull(filter.getRegTo())) {
cb.disjunction().getExpressions().add(cb.between(root.get("regDate"), filter.getRegFrom(), filter.getRegTo()));
}
return predicate;
}
}
}
This is service level:
#Service
public class PhoneService {
#Autowired
private PhoneRepository phoneRepository;
public Phone get(int id) {
Phone phone = phoneRepository.findOne(id);
return nonNull(phone) ? phone : new Phone();
}
public Page<Phone> list(#NonNull PhoneFilter filter) {
PhoneSpecification specification = new PhoneSpecification(filter);
return phoneRepository.findAll(Specifications.where(specification), filter.getPageable());
}
#Data
public static class PhoneFilter {
private Pageable pageable;
private Integer id;
private Timestamp regFrom;
private Timestamp regTo;
private String number;
private String opLogin;
private String opPassword;
private String opName;
private String status;
private String note;
}
}
And entity
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "phone")
#ToString(exclude = {"accounts"})
#EqualsAndHashCode(exclude = {"accounts"})
public class Phone {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#OneToMany(mappedBy = "phone", cascade = CascadeType.DETACH)
private Collection<SocialAccount> accounts;
#Column(name = "reg_date")
private Timestamp regDate;
#Column(name = "number")
private String number;
#Column(name = "operator_url")
private String operatorUrl;
#Column(name = "operator_login")
private String operatorAccLogin;
#Column(name = "operator_pass")
private String operatorAccPassword;
#Column(name = "operator_name")
private String operatorName;
#Column(name = "status")
private String status;
#Column(name = "note")
private String note;
}
I find the mistake.
Method CriteriaBuilder.disjunction() this is factory and each time when I call him I got new Predicate object.
This implementation CriteriaBuilderImpl:
public Predicate disjunction() {
return new CompoundPredicate(this, BooleanOperator.OR);
}
Be careful with it.
I have a CrudRepository that is supposed to make a query with an array (findByIn). In my repository tests it works, but when I try to use the query in my service, it doesn't work. Could someone explain why it doesn't work? Here is my setup (excluding some code irrelevant to the question)
Database model:
#Entity
#Table(name="Place")
public class Place implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "placeId", nullable = false)
private Long placeId;
#Column(name = "owner", nullable = false)
private String owner;
public Long getPlaceId() {
return placeId;
}
public void setPlaceId(Long placeId) {
this.placeId = placeId;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
}
Repository:
#Repository
public interface PlaceRepository extends CrudRepository<Place, Long> {
List<Place> findByPlaceIdIn(Long[] placeId);
}
Service (this is the part not working):
#Service
public class PlaceService {
#Autowired
private PlaceRepository placeRepository;
public List<Place> getPlaces(Long[] placeIds) {
return placeRepository.findByPlaceIdIn(placeIds);
}
}
The problem is that in my service placeRepository.findByPlaceIdIn(placeIds) returns 0 objects if placeIds contains more than one item. If placeIds contains just one item, the query works fine. I tried replacing return placeRepository.findByPlaceIdIn(placeIds) with this piece of code that does the query for every array item one by one (this actually works, but I'd like to get the query work as it should):
ArrayList<Place> places = new ArrayList<Place>();
for (Long placeId : placeIds) {
Long[] id = {placeId};
places.addAll(placeRepository.findByPlaceIdIn(id));
}
return places;
I know that the repository should work, because I have a working test for it:
public class PlaceRepositoryTest {
#Autowired
private PlaceRepository repository;
private static Place place;
private static Place place2;
private static Place otherUsersPlace;
#Test
public void testPlacesfindByPlaceIdIn() {
place = new Place();
place.setOwner(USER_ID);
place2 = new Place();
place2.setOwner(USER_ID);
place = repository.save(place);
place2 = repository.save(place2);
Long[] ids = {place.getPlaceId(), place2.getPlaceId()};
assertEquals(repository.findByPlaceIdIn(ids).size(), 2);
}
}
I also have another repository for other model, which also uses findByIn and it works fine. I can't see any relevant difference between the repositories. I thought it might offer some more details to show the working repository, so I included it below:
Database model:
#Entity
#Table(name="LocalDatabaseRow")
#JsonIgnoreProperties(ignoreUnknown=false)
public class LocalDatabaseRow implements Serializable {
public LocalDatabaseRow() {}
public LocalDatabaseRow(RowType rowType) {
this.rowType = rowType;
}
public enum RowType {
TYPE1,
TYPE2
};
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
#JsonProperty("id")
private Long id;
#JsonProperty("rowType")
#Column(name = "rowType")
private RowType rowType;
public Long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public RowType getRowType() {
return rowType;
}
public void setRowType(RowType rowType) {
this.rowType = rowType;
}
}
Repository:
#Repository
public interface LocalDatabaseRowRepository extends CrudRepository<LocalDatabaseRow, Long> {
List<LocalDatabaseRow> findByRowTypeAndUserIdIn(RowType type, String[] userId);
}
try using a list instead :
findByPlaceIdIn(List placeIdList);
You have a typo in your code (the repository declaration in the service):
#Autowired
private placeRepository placeRepository;
Should be:
#Autowired
private PlaceRepository placeRepository;
I have this Play Model class that I'm trying to modify an object of, and when I want to save it, I get the following exception:
java.lang.RuntimeException: No #javax.persistence.Id field found in class [class models.Contact]
at play.db.ebean.Model._idAccessors(Model.java:39)
at play.db.ebean.Model._getId(Model.java:52)
The class:
#Entity
public class Contact extends Model implements Person {//, Comparable<Contact>{
private Long id;
private Client client;
#Required
private String email;
private String profil_picture;
private Boolean active = new Boolean(true);
private Boolean favorite = new Boolean(false);
#Transient
private Boolean profile_pic_url_init = new Boolean(false);
#Id
#GeneratedValue
public Long getId() {
return id;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="client_id")
public Client getClient(){
return client;
}
public void setClient(Client client){
this.client= client;
}
#Column
public Boolean getFavorite() {
return favorite;
}
public void setFavorite(Boolean is_favorite) {
this.favorite = is_favorite;
}
....
}
The code calling the save() method:
List<Contact> contacts_list = current_client.getContacts();
for (Contact c : contacts_list) {
c.setFavorite(false);
c.save();
}
The class actually has an #Id annotation, so any guesses of why this doesn't work? I tried looking it up on google, but couldn't find much about this error. Thanks in advance!
Move #Id annotation to id field instead of its getter.