I am working on small CRUD parking thing.
My tables Car and Parking are created with liquibase, please see xml.
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.9.xsd">
<changeSet id="202010211812" author="Victor">
<createTable tableName="parking">
<column name="id" type="bigint" autoIncrement="true" defaultOnNull="true">
<constraints primaryKey="true" primaryKeyName="parking_id_pk"/>
</column>
<column name="name" type="varchar(250)"/>
<column name="number_of_places" type="int"/>
<column name="number_of_chargers" type="int"/>
<column name="parking_type" type="varchar(250)"/>
<column name="length_parking_spot" type="double"/>
<column name="width_parking_spot" type="double"/>
</createTable>
<createTable tableName="car">
<column name="id" type="bigint" autoIncrement="true" defaultOnNull="true">
<constraints primaryKey="true" primaryKeyName="car_id_pk"/>
</column>
<column name="make" type="varchar(250)"/>
<column name="model" type="varchar(250)"/>
<column name="price" type="double"/>
<column name="width" type="double"/>
<column name="length" type="double"/>
<column name="car_combustible_type" type="varchar(250)"/>
<column name="year" type="date"/>
<column name="parking_id" type="bigint">
</column>
</createTable>
</changeSet>
</databaseChangeLog>
Here are my classes
Parking :
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class Parking {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
protected int numberOfPlaces;
protected int numberOfChargers;
private ParkingType parkingType;
private double lengthParkingSpot;
private double widthParkingSpot;
@OneToMany
private Set<Car> cars = new HashSet<>();
}
ParkingService :
import com.example.lesson31.domain.Car;
import com.example.lesson31.domain.Parking;
import com.example.lesson31.domain.ParkingType;
import com.example.lesson31.exception.CarBiggerThenParkingSpotException;
import com.example.lesson31.repository.ParkingRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@RequiredArgsConstructor
public class ParkingService extends Parking {
private final ParkingRepository parkingRepository;
public Parking save(Parking parking) {
parkingRepository.save(parking);
return parking;
}
public List<Parking> getAll() {
return parkingRepository.findAll();
}
public Parking parkCarIntoParking(Long parkingId, Car car) throws Exception {
Parking parking = parkingRepository.findById(parkingId)
.orElseThrow(() -> new Exception("Id car not found"));
if (parking.getNumberOfPlaces() == 0) {
throw new Exception("no more empty parking spaces :(");
}
isLpgOrNo(car, parking);
isElectricOrNo(car, parking);
isCarBiggerThenTheWidthSpot(car, parking);
parking.getCars()
.add(car);
return parking;
}
public Parking getParkingById(Long id) throws Exception {
return parkingRepository.findById(id)
.orElseThrow(() -> new Exception("Car Id not found"));
}
public Parking updateParking(Long id, Parking parking) {
Parking parking1 = parkingRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Custom error message"));
parking1.setName(parking.getName());
parking1.setNumberOfPlaces(parking.getNumberOfPlaces());
parking1.setNumberOfChargers(parking.getNumberOfChargers());
parking1.setWidthParkingSpot(parking.getWidthParkingSpot());
parking1.setLengthParkingSpot(parking.getLengthParkingSpot());
return parkingRepository.save(parking);
}
public void deleteParking(Long id) throws Exception {
Parking parkingForDelete = parkingRepository.findById(id)
.orElseThrow(() -> new Exception("grgreg"));
parkingRepository.deleteById(parkingForDelete.getId());
}
public void isLpgOrNo(Car car, Parking parking) throws Exception {
if (car.getCarCombustibleType()
.equalsIgnoreCase("lpg")
&& parking.getParkingType()
.equals(ParkingType.UNDERGROUND)) {
throw new Exception("Parking is not for cars with LPG :(");
}
}
public void isElectricOrNo(Car car, Parking parking) throws Exception {
if (car.getCarCombustibleType()
.equalsIgnoreCase("electric") && parking.getNumberOfChargers() == 0) {
throw new Exception("No chargers available");
}
}
public void isCarBiggerThenTheWidthSpot(Car car, Parking parking) throws CarBiggerThenParkingSpotException {
if (car.getWidth() > parking.getWidthParkingSpot()) {
throw new CarBiggerThenParkingSpotException("Vehicle width is bigger then the parking spot width!");
}
}
}
ParkingController :
import com.example.lesson31.command.CarCommand;
import com.example.lesson31.command.ParkingCommand;
import com.example.lesson31.domain.Car;
import com.example.lesson31.domain.Parking;
import com.example.lesson31.dto.ParkingDto;
import com.example.lesson31.service.ParkingService;
import lombok.RequiredArgsConstructor;
import org.modelmapper.ModelMapper;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/parking")
@RequiredArgsConstructor
public class ParkingController {
private final ParkingService parkingService;
public final ModelMapper modelMapper;
@PostMapping("/{id}")
public ResponseEntity<ParkingDto> parkCar(@PathVariable Long id, @RequestBody CarCommand carCommand) throws Exception {
return new ResponseEntity<>(modelMapper.map(parkingService.parkCarIntoParking(id, modelMapper.map(carCommand, Car.class)), ParkingDto.class), HttpStatus.OK);
}
@PostMapping
public ResponseEntity<ParkingDto> saveParking(@RequestBody ParkingCommand parkingCommand) {
return new ResponseEntity<>(modelMapper.map(parkingService.save(modelMapper.map(parkingCommand, Parking.class)), ParkingDto.class), HttpStatus.CREATED);
}
@GetMapping
public ResponseEntity<List<ParkingDto>> getAllParkings() {
return new ResponseEntity<>(parkingService.getAll().stream()
.map(parkings -> modelMapper.map(parkings, ParkingDto.class))
.collect(Collectors.toList()), HttpStatus.OK);
}
@PutMapping("/{id}")
public ResponseEntity<ParkingDto> updateParking(@PathVariable Long id, @RequestBody ParkingCommand parkingCommand) {
return new ResponseEntity<>(modelMapper.map(parkingService.updateParking(id, modelMapper.map(parkingCommand, Parking.class)), ParkingDto.class), HttpStatus.OK);
}
@DeleteMapping("/{id}")
public HttpStatus deleteParking(@PathVariable Long id) throws Exception {
parkingService.deleteParking(id);
return HttpStatus.OK;
}
}
ParkingCommand :
import com.example.lesson31.domain.ParkingType;
import lombok.Data;
@Data
public class ParkingCommand {
private String name;
private int numberOfPlaces;
private int numberOfChargers;
private ParkingType parkingType;
private int lengthParkingSpot;
private int widthParkingSpot;
}
ParkingDto :
import com.example.lesson31.domain.ParkingType;
import lombok.Data;
@Data
public class ParkingDto {
private String name;
private int numberOfPlaces;
private ParkingType parkingType;
}
Car :
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDate;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class Car {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String make;
private String model;
private double price;
private double length;
private double width;
private CarCombustibleType carCombustibleType;
private LocalDate year;
@ManyToOne
@JoinColumn(name = "parking_id")
private Parking parking;
}
CarService:
import com.example.lesson31.domain.Car;
import com.example.lesson31.repository.CarRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@RequiredArgsConstructor
public class CarService {
private final CarRepository carRepository;
public Car save(Car car) {
return carRepository.save(car);
}
public List<Car> getAll() {
return carRepository.findAll();
}
public Car updateCar(Long id, Car car) throws Exception {
Car carForUpdate = carRepository.findById(id)
.orElseThrow(() -> new Exception("Car Id not found"));
carForUpdate.setMake(car.getMake());
carForUpdate.setModel(car.getModel());
carForUpdate.setPrice(car.getPrice());
carForUpdate.setLength(car.getLength());
carForUpdate.setWidth(car.getWidth());
carForUpdate.setCarCombustibleType(car.getCarCombustibleType());
return carRepository.save(car);
}
public void deleteCar(Long id) throws Exception {
Car carForDelete = carRepository.findById(id)
.orElseThrow(() -> new Exception("Car id not found"));
carRepository.deleteById(carForDelete.getId());
}
}
CarController:
import com.example.lesson31.command.CarCommand;
import com.example.lesson31.command.ParkingCommand;
import com.example.lesson31.domain.Car;
import com.example.lesson31.dto.CarDto;
import com.example.lesson31.repository.CarRepository;
import com.example.lesson31.service.CarService;
import lombok.RequiredArgsConstructor;
import org.modelmapper.ModelMapper;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/car")
@RequiredArgsConstructor
public class CarController {
public final CarService carService;
public final CarRepository carRepository;
public final ModelMapper modelMapper;
@PostMapping
public ResponseEntity<CarDto> saveCar(@RequestBody CarCommand carCommand) {
return new ResponseEntity<>(modelMapper.map(carService.save(modelMapper.map(carCommand, Car.class)), CarDto.class), HttpStatus.CREATED);
}
@GetMapping
public ResponseEntity<List<CarDto>> getAllCars() {
return new ResponseEntity<>(carService.getAll()
.stream()
.map(car -> modelMapper.map(car, CarDto.class))
.collect(Collectors.toList()), HttpStatus.OK);
}
@PutMapping("/{id}")
public ResponseEntity<CarDto> updateCar(@PathVariable Long id, @RequestBody ParkingCommand parkingCommand) throws Exception {
return new ResponseEntity<>(modelMapper.map(carService.updateCar(id, modelMapper.map(parkingCommand, Car.class)), CarDto.class), HttpStatus.OK);
}
@DeleteMapping("/{id}")
public HttpStatus deleteCar(@PathVariable Long id) throws Exception {
carService.deleteCar(id);
return HttpStatus.OK;
}
}
CarCommand:
import lombok.Data;
import java.time.LocalDate;
@Data
public class CarCommand {
private String make;
private String model;
private double price;
private double length;
private double width;
private String carCombustibleType;
private LocalDate year;
}
CarDto:
import lombok.Data;
import java.time.LocalDate;
@Data
public class CarDto {
private String make;
private String model;
private double price;
private LocalDate year;
private CarCombustibleType carCombustibleType;
}
I add car and parking by POSTMAN POST request into database.
See example of car and parking :
Car :
{
"make" : "Fiat",
"model" : "Abarth",
"price" : "21500",
"width" : "3.5",
"length" : "3.5",
"carCombustibleType" :"0",(0= BENZINE, 1 = LPG, 2 =ELECTRIC, 3 = DIESEL)
"year" : "2020-08-15"
}
Parking:
}
"name": "WestParking",
"numberOfPlaces": 25,
"numberOfChargers": 5,
"parkingType": "1", //(1= OUTSIDE / 2= UNDERGROUND)
"length": 3.5,
"width": 3.0
}
When I want to park a car inside the parking by POSTMAN I get the error:
Cannot invoke "com.example.lesson31.domain.CarCombustibleType.equals(Object)" because the return value of "com.example.lesson31.domain.Car.getCarCombustibleType()" is null
This is my JSON postman POST request:
http://localhost:8080/parking/1
With the follozing body
{
"id" : "1"
}
Can anyoane advice what I do wrong ?
CodePudding user response:
Your http://localhost:8080/parking/1
endpoint expects a CarCommand
object as a request body, like the one you've shown:
{
"make" : "Fiat",
"model" : "Abarth",
"price" : "21500",
"width" : "3.5",
"length" : "3.5",
"carCombustibleType" :"0",(0= BENZINE, 1 = LPG, 2 =ELECTRIC, 3 = DIESEL)
"year" : "2020-08-15"
}
But when you POST
{
"id" : "1"
}
the fields of the carCommand
used in
@PostMapping("/{id}")
public ResponseEntity<ParkingDto> parkCar(@PathVariable Long id, @RequestBody CarCommand carCommand) throws Exception {
return new ResponseEntity<>(modelMapper.map(parkingService.parkCarIntoParking(id, modelMapper.map(carCommand, Car.class)), ParkingDto.class), HttpStatus.OK);
}
are set to null
, thus the modelMapper
-mapped Car
instance also has null fields and thus your error the return value of "com.example.lesson31.domain.Car.getCarCombustibleType()" is null
The proper way to make sure the request data you receive is valid is by using bean validation. See https://www.baeldung.com/spring-boot-bean-validation for more info.
CodePudding user response:
you should not use double type data as it cannot take null, you should use Double type data instead and similar different parts