Embeded object is always null? - spring-boot

I have following Request body which I am trying to insert into the database:
{
"vin": "1HGCR2F3XFA027534",
"latitude": 41.803194,
"longitude": -88.144406,
"timestamp": "2017-05-25T17:31:25.268Z",
"fuelVolume": 1.5,
"speed": 85,
"engineHp": 240,
"checkEngineLightOn": false,
"engineCoolantLow": true,
"cruiseControlOn": true,
"engineRpm": 6300,
"tires": {
"frontLeft": 34,
"frontRight": 36,
"rearLeft": 29,
"rearRight": 34
}
}
I cannot insert it as Tires object is always mapped as null. I don't think the json object is able to map to tires object.
Here are snippets
In controller:
#RequestMapping(method = RequestMethod.POST, value = "/readings")
public void readVehicleStatus(#RequestBody VehicleStatus vehicleStatus){
vehicleStatusService.readVehicleStatus(vehicleStatus);
}
VehicleStatus.java
#Entity
public class VehicleStatus {
#Id
private String vin;
private Double latitude;
private Double longitude;
private Double fuelVolume;
private int speed;
private int engineHp;
private int engineRpm;
private boolean checkEngineLightOn;
private boolean engineCoolantLow;
private boolean cruiseControlOn;
#Embeded
private Tires tires;
/* getters and setters created */
}
Tires.java
#Embeddable
public class Tires {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
int id;
private int frontLeft;
private int frontRight;
private int rearLeft;
private int rearRight;
/* getters and setters included */
}

In your VehicleStatus the tires json property is named vehicleTire but in the json is named tires, that's why is always null, so you should add #JsonProperty(value="tires").
Here is the full code:
#Entity
public class VehicleStatus implements Serializable{
#Id
private String vin;
private Double latitude;
private Double longitude;
private Double fuelVolume;
private int speed;
private int engineHp;
private int engineRpm;
private boolean checkEngineLightOn;
private boolean engineCoolantLow;
private boolean cruiseControlOn;
#OneToOne(mappedBy = "vehicleStatus",cascade=CascadeType.ALL)
#JoinColumn(name = "id")
#JsonProperty(value="tires") // here is the key :)
private Tires vehicleTire;
// Getters && Setters
}
#Entity
public class Tires implements Serializable{
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
Integer id;
private Integer frontLeft; // NB try always to use wrapper type rather than primitive in jpa
private Integer frontRight;
private Integer rearLeft;
private Integer rearRight;
#OneToOne
private VehicleStatus vehicleStatus;
// Getters && Setters
}
TiresRepository:
public interface TiresRepository extends JpaRepository<Tires, Integer>{
}
VehicleStatusRepository:
public interface VehicleStatusRepository extends JpaRepository<VehicleStatus, String>{
}
Example of controller :
#RestController
#RequestMapping
class MyController {
#Autowired
private VehicleStatusRepository vehicleStatusRepository;
#RequestMapping(method = RequestMethod.POST, value = "/readings")
public void readVehicleStatus(#RequestBody VehicleStatus vehicleStatus){
vehicleStatusRepository.saveAndFlush(vehicleStatus);
}
}
Main class :
#SpringBootApplication
#EnableAutoConfiguration
public class SpringStackOverflowSolutionApplication {
public static void main(String[] args) {
SpringApplication.run(SpringStackOverflowSolutionApplication.class, args);
}
}
NB: do not forget cascadeAll, else the tires object will not be saved in the database and you will get the following exception :
org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : package.VehicleStatus.vehicleTire -> package.Tires

Related

how to properly design a controller and a jsp page for an entity that has three keys, two external and one internal?

I'm trying to make a Spring MVC application.I have 4 entities(Company,Pass_in_trip,Passenger,Trip) Pass_in_trip has 3 keys consisting of Passenger, Trip and Timestamp, I don't know how to properly issue a key and how to transfer it through the jsp page to the controller, and how to issue the controller itself, can anyone tell me?and also an interesting question is how to make a request to the database to search for a record using three keys.
Thanks
here's what I was able to write at the moment, see if there are any errors somewhere
#Entity
#Table(name="company")
public class Company implements Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name="id_comp")
private int id_comp;
#Column(name="name")
private String name;
//Getters and Setters
#Entity
#Table (name="pass_in_trip")
public class Pass_in_trip implements Serializable {
#EmbeddedId
private KeysPass_in_trip key=new KeysPass_in_trip();
#Column(name="place")
private String place;
//Getters and Setters
#Embeddable
public class KeysPass_in_trip implements Serializable{
#NotNull
#JoinColumn(name="date")
private Timestamp date=new Timestamp(System.currentTimeMillis());
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "id_psg")
private Passenger id_psg=new Passenger();
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "trip_no" )
private Trip trip_no=new Trip();
//Getters and Setters
//#Override hashCode and equals
#Entity
#Table(name="passenger")
public class Passenger implements Serializable {
#Column(name="name")
private String name;
#NotNull
#Id
#Column(name="id_psg")
#GeneratedValue(strategy = IDENTITY)
private int id_psg;
//Getters and Setters
#Entity
#Table(name="trip")
public class Trip implements Serializable {
#NotNull
#Id
#Column(name="trip_no")
private int trip_no;
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "id_comp")
private Company comp=new Company();
#Column(name="plane")
private String plane;
#Column(name="town_from")
private String town_from;
#Column(name="town_to")
private String town_to;
#Column(name="time_out")
private Timestamp time_out;
#Column(name="time_in")
private Timestamp time_in;
//Getters and Setters
Conroller
#Controller
#RequestMapping("/pass_in_trip/")
public class Aero_Controller_Pass_in_trip {
#Autowired
private Aero_DAO service;
public void setService(Aero_DAO service) {
this.service = service;
}
#RequestMapping(method=RequestMethod.GET)
public String list(Model uiModel) {
List <Pass_in_trip> pass_in_trip=service.findallPass_in_trip();
uiModel.addAttribute("pass_in_trip",pass_in_trip);
return "/pass_in_trip/list";
}
#PreAuthorize("hasRole('ROLE_Admin')")
#RequestMapping(value="delete/{id}",method=RequestMethod.GET)
public String delete(#PathVariable("id")int id, Model uiModel) {
if(service.findByIdPass_in_Trip(id)!=null)
service.delete_Pass_in_trip(id);
return "redirect:/pass_in_trip/";
}
#PreAuthorize("hasRole('ROLE_Admin')")
#RequestMapping(value="update/{id}",method=RequestMethod.GET)
public String updateform(#PathVariable("id")int id, Model uiModel) {
System.out.println("upform");
uiModel.addAttribute("pass_in_trip",service.findByIdPass_in_Trip(id));
System.out.println("upform2");
return "/pass_in_trip/edit";
}
#RequestMapping(value="update/0",method=RequestMethod.GET)
public String newform(Model uiModel) {
System.out.println("Привет!");
return "/pass_in_trip/edit";
}
#PreAuthorize("hasRole('ROLE_Admin')")
#RequestMapping(value="update/{id}",method = RequestMethod.POST)
public String update(Pass_in_trip pass_in_trip,BindingResult bindingResult,Model uiModel,HttpServletRequest httprervletrequest , RedirectAttributes redirectatributes) {
if (bindingResult.hasErrors()) {
uiModel.addAttribute("pass_in_trip", pass_in_trip);
return "pass_in_trip/update";}
service.save(pass_in_trip);
return "redirect:/pass_in_trip/";
}
}
List.jsp
interested in this part:
<s:authorize access="hasRole('ROLE_Admin')">
<td> To change </td>
<td> Delete </td>
</s:authorize>

Why I am receiving empty array?

I am doing a project in Spring and Postgres. I am getting this empty column when I try to call a request with Postman. As you can see, it returns everything except ingredient column.
{
"recept_id": 8,
"recept_name": "conceptual",
"nation_id": 1,
"type_id": 1,
"isvegan": true,
"isvegetarian": true,
"photo": null,
"video": null,
"ingredient": [],
"level_id": 5,
"recept_view": 1,
"company_id": 4,
"ratinglvl": 5
}
However, in Postgres, this column has data ({1,2,3}). The data type of the ingredient column is an integer[] in Postgres. I inserted data to ingredient to Postgres manually.
While in Spring, I am using a simple CRUDrepository.
Entity:
#Data
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "recept")
public class Recept {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long recept_id;
#Column
private String recept_name;
private long nation_id;
private long type_id;
private boolean isvegan;
private boolean isvegetarian;
private File photo;
private File video;
#ElementCollection(targetClass=Long.class)
private List<Long> ingredient;
private short level_id;
private long recept_view;
private long company_id;
private short ratinglvl;
}
Controller:
#RestController
public class ReceptController {
private final ReceptService receptService;
public ReceptController(ReceptService receptService) {
this.receptService = receptService;
}
#RequestMapping(value="/recept",method= RequestMethod.GET, headers = "Accept=application/json")
public ResponseEntity<?> getAll() {
return ResponseEntity.ok(receptService.getAll());
}
Repository:
public interface ReceptRepository extends CrudRepository<Recept, Long> {}
Service:
#Service
public class ReceptService {
private final ReceptRepository receptRepository;
private final IngredientRepository ingredientRepository;
public ReceptService(ReceptRepository receptRepository, IngredientRepository ingredientRepository) {
this.receptRepository = receptRepository;
this.ingredientRepository = ingredientRepository;
}
public List<Recept> getAll(){
return (List<Recept>)receptRepository.findAll();
}
Don't know why it doesn't return it.
#ElementCollection is meant to collect the values of a column in a related table -not to denote a PostgreSQL array type.
In order to use Postgresql arrays, you need to define a custom type. Thankfully the hibernate-types library already provides a ListArrayType out of the box. This will allow you to define your entity like:
#Data
#NoArgsConstructor
#AllArgsConstructor
#Entity
#TypeDef(
name = "list-array"
typeClass = ListArrayType.class
)
#Table(name = "recept")
public class Recept {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long recept_id;
#Column
private String recept_name;
private long nation_id;
private long type_id;
private boolean isvegan;
private boolean isvegetarian;
private File photo;
private File video;
#ElementCollection(targetClass=Long.class)
#Type(type = "list-array)
#Column(
name = "ingredient",
columnDefinition = "integer[]"
)
private List<Long> ingredient;
private short level_id;
private long recept_view;
private long company_id;
private short ratinglvl;
}

I don't know why the double values are displayed in postman. Is the my code correct?

This is my Book class:
#Entity
#Table(name="book")
public class Book {
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
#ManyToOne(targetEntity=Category.class,cascade=CascadeType.ALL,fetch=FetchType.LAZY)
#JoinColumn(name="CategoryId")
public Category category;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(length=10)
private int book_id;
#Column(length=128)
private String title;
#Column(length=64)
private String author;
#Column(length=200)
private String description;
#Column(length=10)
private int ISBN;
#Column(length=10)
private float price;
private Date published_Date;
#Lob
#Column
#Basic(fetch = FetchType.LAZY)
private byte[] icon;
//getter and setter
}
This is my Category class:
#Entity
#Table(name="category1")
public class Category {
#Id
#Column(length=12)
#GeneratedValue(strategy=GenerationType.AUTO)
public int CategoryId;
#Column(length=50)
public String CategoryName;
//#JsonBackReference
#OneToMany(mappedBy="category")
private List<Book> books = new ArrayList<Book>();
//getter and setter
}
The relationship between them is one to many.
This is my Category Service class
#Service
#Transactional
public class AdminServiceImpl implements AdminService {
#Autowired
private CategoryDao dao;
#Autowired
private BookDao dao1;
#Override
public List<Category> getAllCategory(){
return dao.findAll();
}
}
My Controller class
#RestController
#RequestMapping("/bookstore")
public class CategoryController {
#Autowired
private AdminService service;
#GetMapping("/GetAllCategory")
private ResponseEntity<List<Category>> getAllCategory() {
List<Category> catlist = service.getAllCategory();
return new ResponseEntity<List<Category>>(catlist, new HttpHeaders(), HttpStatus.OK);
}
}
My category table already has data.When i try to display them it is showing double values.
Displaying values using Postman
The Category table in the Database: Database table
Jackson's ObjectMapper uses the Java bean pattern and it expects the following
public class Foo {
public Object bar;
public Object getBar() {...}
public void setBar(Object bar) {...}
}
The getters and setters start with get and set, respectively, followed by the corresponding field name with its first letter capitalized.
Change
CategoryId to categoryId (first letter lowercase)
and
CategoryName to categoryName

ModelMapper issue with mapping basic POJOS

I have 2 basic POJOs that i use to build a json object :
public class ProductCreateRequestModel {
private String name;
private double price;
private int qty;
private String imgPath;
private CategoryRequestCreateProductModel category;
}
public class CategoryRequestCreateProductModel {
private String name;
private String categoryKeyId;
}
Basically it allow me to use a simple json like this one :
{
"name": "Pizza,
"price": 344.0,
"qty": 15,
"imgPath": "new/pathImage",
"category": {
"categoryKeyId": "23ume70Fu6yqyGUWfQkW110P4ko3gZ",
"name": "Starter"
}
}
I want to send this JSON and persist datas and i expect an object in return that i build with this POJO:
public class ProductRest {
private String productKeyId;
private String name;
private double price;
private int qty;
private String imgPath;
private CategoryRest category;
}
In my controller i just have to call a method which use PostMapping
#PostMapping(
consumes = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE },
produces = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE }
)
public ProductRest createProduct(#RequestBody ProductCreateRequestModel productCreateRequestModel) throws Exception {
ProductRest returnValue = new ProductRest();
if(productCreateRequestModel.getName().isEmpty() || productCreateRequestModel.getPrice() <= 0)
throw new ApplicationServiceException(ErrorMessages.MISSING_REQUIRED_FIELDS.getErrorMessage());
ModelMapper modelMapper = new ModelMapper();
ProductDto productDto = modelMapper.map(productCreateRequestModel, ProductDto.class);
ProductDto createdProduct = productService.createProduct(productDto);
returnValue = modelMapper.map(createdProduct, ProductRest.class);
return returnValue;
}
My service layer is actually doing nothing special :
#Override
public ProductDto createProduct(ProductDto productDto) {
return productDto;
}
My DTO layer contains the following fields :
#Getter #Setter
public class ProductDto implements Serializable {
// ommit this member and do not generate getter / setter
#Getter(AccessLevel.NONE)
#Setter(AccessLevel.NONE)
private static final long serialVersionUID = 1L;
private Long id;
private String productKeyId;
private String name;
private double price;
private int availableQty;
private String imgPath;
private CategoryDto category = new CategoryDto();
}
#Getter #Setter
public class CategoryDto implements Serializable {
#Getter(AccessLevel.NONE)
#Setter(AccessLevel.NONE)
private static final long serialVersionUID = 1L;
private long id;
private String categoryKeyId;
private String name;
private CategoryDto parentCategory;
private List<CategoryDto> subCategories;
private String parentCategoryKeyId;
private Long parentCategoryId;
}
While trying to run this basic code I obtain an error message :
java.lang.NumberFormatException: For input string: "23ume70Fu6yqyGUWfQkW110P4ko3gZ"

How to lazy fetch with spring data repository?

Database Tables
post
tag
ref_post_tag
post and tag has a Many-to-Many relationship
Entities
Post
#Entity
#Table(name = "post")
public class Post implements Serializable{
private static final long serialVersionUID = 1783734013146305964L;
public enum Status {
DRAFT, REMOVED, LIVE;
}
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private String id;
#Column(name = "title")
private String title;
#Column(name = "create_time")
private LocalDateTime createTime;
#Column(name = "update_time")
private LocalDateTime updateTime;
#Column(name = "content")
private String content;
#Column(name = "status")
#Enumerated(EnumType.STRING)
private Status status;
#ManyToMany
#JoinTable(
name = "ref_post_tag",
joinColumns = #JoinColumn(name="post_id",referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name="tag_id", referencedColumnName = "id"))
private List<Tag> tagList;
...
}
Tag
#Entity
#Table(name="tag")
public class Tag implements Serializable{
private static final long serialVersionUID = -7015657012681544984L;
#Id
#Column(name="id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column(name="name")
private String name;
#Column(name="description")
private String description;
#ManyToMany(mappedBy = "tagList")
private List<Post> postList;
public Integer getId() {
return id;
}
...
}
Tag Repo
public interface TagRepo extends CrudRepository<Tag, Integer>{
}
service implementation
#Service
public class TagServiceImpl implements TagService{
#Autowired
private TagRepo tagRepo;
#Override
public void addTag(Tag tag) {
tagRepo.save(tag);
}
#Override
public Tag getTag(Integer id) {
Tag tag = tagRepo.findOne(id);
return tag;
}
#Override
public List<Tag> findAllTags() {
return CollectionUtil.toArrayList(tagRepo.findAll());
}
}
sample test (Updated)
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = TestContextConfiguration.class)
#Transactional
public abstract class ServiceTest {
}
public class TagServiceTest extends ServiceTest{
#Autowired
private TagService tagService;
#Autowired
private TagRepo tagRepo;
#Test
#Transactional
public void addTag() throws Exception {
Tag tag = new Tag();
tag.setName("new tag");
tag.setDescription("this is a new tag");
tagService.addTag(tag);
Tag tagCreated = tagRepo.findOne(tag.getId());
assertNotNull(tagCreated);
assertEquals(tagCreated.getName(), tag.getName());
}
#Test
public void getTag() throws Exception {
Tag tag = tagService.getTag(1); // tag "java" has an ID of "1"
assertNotNull(tag);
assertEquals(tag.getName(), "java");
assertEquals(143,tag.getPostList().size()); // 143 posts under tag "java"
}
}
Question
The sample test case passes. It means that the postList in fetched Tag is also eagerly fetched and filled.
Is Spring data repository's methods eagerly fetching by default?
If yes, what is the best way to change this to lazy fetching?

Resources