Deserialize DTO with jhipster's StringFilter - spring

I have endpoint that i send data from other backend:
#GetMapping("/")
#PageableAsQueryParam
public ResponseEntity<Page<Dto>> getAll(
#RequestHeader("Authorization") String token,
#RequestParam("page") Integer page,
#RequestParam("pageSize") Integer pageSize,
String criteria
) throws IOException {
I see in debug that String criteria has data:
DocCriteria(id=null, symbol=StringFilter [contains=abcdef, ])
After changing String criteria to: DocCriteria criteria
In debug i see that all fields of DocCriteria are null.
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.extern.jackson.Jacksonized;
import tech.jhipster.service.Criteria;
import tech.jhipster.service.filter.InstantFilter;
import tech.jhipster.service.filter.LongFilter;
import tech.jhipster.service.filter.StringFilter;
import tech.jhipster.service.Criteria;
import lombok.Data;
import java.io.Serializable;
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
#Jacksonized
public class DocCriteria implements Serializable, Criteria {
private static final long serialVersionUID = 1L;
private LongFilter id;
private StringFilter symbol;
}
I also tried to serialize object from String:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
final DocCriteria pojo = objectMapper.convertValue(criteria, DocCriteria.class);
But then i have got an error:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `...DocCriteria$DocCriteriaBuilder`
(although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value
('DocCriteria(id=null, symbol=StringFilter [contains=abcdef, ]')
What should i do to make Spring deserialize that object correctly ?
<spring-boot.version>2.6.6</spring-boot.version>
<java.version>1.8</java.version>
<dependency>
<groupId>tech.jhipster</groupId>
<artifactId>jhipster-dependencies</artifactId>
<version>7.8.0</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>tech.jhipster</groupId>
<artifactId>jhipster-framework</artifactId>
<version>7.8.0</version>
</dependency>
EDIT:
without using lombok:
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import tech.jhipster.service.Criteria;
import tech.jhipster.service.filter.InstantFilter;
import tech.jhipster.service.filter.LongFilter;
import tech.jhipster.service.Criteria;
import java.io.Serializable;
import java.util.Objects;
public class DocCriteria implements Serializable {
private static final long serialVersionUID = 1L;
private LongFilter id;
private StringFilter symbol;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DocCriteria that = (DocCriteria) o;
return Objects.equals(id, that.id) && Objects.equals(symbol, that.symbol);
}
#Override
public int hashCode() {
return Objects.hash(id, symbol);
}
public LongFilter getId() {
return id;
}
public void setId(LongFilter id) {
this.id = id;
}
public StringFilter getSymbol() {
return symbol;
}
public void setSymbol(StringFilter symbol) {
this.symbol= symbol;
}
public DocCriteria() {
}
#JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public DocCriteria(
#JsonProperty("id") LongFilter id,
#JsonProperty("symbol") StringFilter symbol,
) {
this.id = id;
this.symbol = symbol;
}
}
I have the same issue.

Related

Why am I getting null for the date when I create a Todo entity?

What is wrong with my to-do application? I want the user to be able to add a todo and have it be saved in my MySQL database with the time it was created, but I don't know what I'm doing wrong.
I am new to learning Springboot and would appreciate any suggestions or advice.
Todo Entity:
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import javax.persistence.*;
import java.util.Date;
#Entity(name = "Todo")
#NoArgsConstructor
#Table(name = "todos")
public class Todo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#Column(name="description")
private String description;
#Column(name="target_date")
#CreationTimestamp
private Date targetDate;
public Todo(String description) {
this.description = description;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Date getTargetDate() {
return targetDate;
}
public void setTargetDate(Date targetDate) {
this.targetDate = targetDate;
}
#Override
public String toString() {
return "Todo{" +
"id=" + id +
", description='" + description + '\'' +
", targetDate=" + targetDate +
'}';
}
}
Adding a Todo with Spring Data JPA
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import javax.transaction.Transactional;
import java.util.List;
#Repository
#Component
public interface TodoRepository extends JpaRepository<Todo, Integer> {
#Modifying
#Query(value = "INSERT INTO todos (description) VALUES (:description)", nativeQuery=true)
#Transactional
void addTodo(#Param("description") String description);
}
TodoController
#RestController
#RequestMapping(value = "/api/v1/todos")
#AllArgsConstructor
public class TodoController {
#Autowired
private ITodoService todoService;
#PostMapping(value = "/add-todo")
public String addTodo(#RequestParam String description) {
Todo todo = new Todo();
todo.setDescription(description);
todoService.addTodo(todo);
return todo.toString();
}
after getting a post request, the target_date is getting NULL in MySQL
I assume you can solve it by using persist():
#Autowired EntityManager entityManager;
#PostMapping(value = "/add-todo")
public String addTodo(#RequestParam String description) {
Todo todo = new Todo();
todo.setDescription(description);
entityManager.persist(todo);
return todo.toString();
}

created_by is always set to null in the database and Version does not work properly

I am trying to implement one entity to see how Auditing works in spring. I have tow issues here:
First issue is that "created_by" field is always set to null in the database, although I have created a bean of AuditAware and set it to myself.
Second issue is that whenever I want to insert something into the country table, it forces me to provide the version number. It is not the behaviour I want as I expect version gets picked up by the spring itself
I appreciate if someone could help me to tackle these two issues.
AbstractMethodEntity is as follow:
package com.xx.xxx.hotel;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.time.LocalDateTime;
#MappedSuperclass
#EntityListeners({ AuditingEntityListener.class })
public abstract class AbstractModelEntity<U> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "created_by")
#CreatedBy
private U CreatedBy;
#Column(name = "create_date")
#CreatedDate
private LocalDateTime createdDate;
#Version
private long version;
#Column(name = "modified_by")
#LastModifiedBy
private U lastModifiedBy;
#Column(name = "modified_date")
#LastModifiedDate
private LocalDateTime lastModifiedDate;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
public U getCreatedBy() {
return CreatedBy;
}
public void setCreatedBy(U createdBy) {
CreatedBy = createdBy;
}
public LocalDateTime getCreatedDate() {
return createdDate;
}
public void setCreatedDate(LocalDateTime createdDate) {
this.createdDate = createdDate;
}
public U getLastModifiedBy() {
return lastModifiedBy;
}
public void setLastModifiedBy(U lastModifiedBy) {
this.lastModifiedBy = lastModifiedBy;
}
public LocalDateTime getLastModifiedDate() {
return lastModifiedDate;
}
public void setLastModifiedDate(LocalDateTime lastModifiedDate) {
this.lastModifiedDate = lastModifiedDate;
}
}
The Country entity:
package com.xx.xxx.hotel.service.country;
import com.miraftabi.hossein.hotel.AbstractModelEntity;
import org.hibernate.envers.AuditOverride;
import org.hibernate.envers.Audited;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
#Entity
#Audited
#AuditOverride(forClass = AbstractModelEntity.class, isAudited = true)
#Table(name = "country")
public class CountryEntity extends AbstractModelEntity<String> {
#Column(name = "name", nullable = false)
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
AuditAwareImpl file:
package com.xx.xxx.hotel.service;
import org.springframework.data.domain.AuditorAware;
import java.util.Optional;
public class AuditorAwareImpl implements AuditorAware<String> {
#Override
public Optional<String> getCurrentAuditor() {
return Optional.of("Hossein");
}
}
AuditConfiguraiton file:
package com.xx.xxx.hotel.config;
import com.xx.xxx.hotel.service.AuditorAwareImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
#Configuration
#EnableJpaAuditing(auditorAwareRef = "auditorAware")
public class AuditConfiguration {
#Bean
public AuditorAware<String> auditorAware() {
return new AuditorAwareImpl();
}
}
RepositoryConfiguration file:
package com.xx.xxx.hotel.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.envers.repository.support.EnversRevisionRepositoryFactoryBean;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#Configuration
#EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class)
public class RepositoryConfiguration {
}
CountryRevisionRepository file:
package com.xx.xxx.hotel.service.country;
import org.springframework.data.repository.history.RevisionRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface CountryRevisionRepository extends RevisionRepository<CountryEntity, Long, Integer> {
}
Application.properties:
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://localhost:3306/hotel
spring.datasource.username=${DATABASE_USERNAME}
spring.datasource.password=${DATABASE_PASSWORD}
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.open-in-view=false
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true

Unique index or primary key violation: "PRIMARY KEY ON PUBLIC.CAR(ID) : While calling the POST service

CarController.java
package com.mytaxi.controller;
import java.util.List;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import com.mytaxi.controller.mapper.CarMapper;
import com.mytaxi.datatransferobject.CarDTO;
import com.mytaxi.datatransferobject.CarDTO;
import com.mytaxi.domainobject.CarDO;
import com.mytaxi.domainvalue.Type;
import com.mytaxi.exception.ConstraintsViolationException;
import com.mytaxi.exception.EntityNotFoundException;
import com.mytaxi.service.car.CarService;
#RestController
#RequestMapping("v1/cars")
public class CarController
{
private final CarService carService;
#Autowired
public CarController(final CarService carService)
{
this.carService = carService;
}
#PostMapping
#ResponseStatus(HttpStatus.CREATED)
public CarDTO createCar(#Valid #RequestBody CarDTO carDTO) throws ConstraintsViolationException
{
CarDO carDO = CarMapper.makeCarDO(carDTO);
carDTO = CarMapper.makeCarDTO(carDO);
carService.create(carDO);
return carDTO;
}
}
CarDO.java
package com.mytaxi.domainobject;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.Max;
import com.mytaxi.domainvalue.Type;
#Entity
#Table(
name = "car",
uniqueConstraints = #UniqueConstraint(name = "uc_licensePlate", columnNames = {"licensePlate"})
)
public class CarDO
{
#Id
#Column(nullable = false)
#GeneratedValue
private Long id;
#Column(nullable = false)
#Enumerated(EnumType.STRING)
private Type manufacturer;
#Column(nullable = false)
private String licensePlate;
#Column(nullable = false)
private Integer seatCount;
#Column(nullable = false)
private String engineType;
#Column(nullable = false)
#org.hibernate.annotations.Type(type="yes_no")
private Boolean convertible;
#Column
#Max(5)
private Integer rating;
#Column(nullable = false)
#org.hibernate.annotations.Type(type="yes_no")
private Boolean isFunctioning = true;
#Column(nullable = false)
#org.hibernate.annotations.Type(type="yes_no")
private Boolean isBooked = false;
public Boolean getIsFunctioning()
{
return isFunctioning;
}
public void setIsFunctioning(Boolean isFunctioning)
{
this.isFunctioning = isFunctioning;
}
public CarDO(Type manufacturer, String licensePlate, Integer seatCount,
String engineType, Boolean convertible)
{
this.manufacturer = manufacturer;
this.licensePlate = licensePlate;
this.seatCount = seatCount;
this.engineType = engineType;
this.convertible = convertible;
}
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public Type getManufacturer()
{
return manufacturer;
}
public void setManufacturer(Type manufacturer)
{
this.manufacturer = manufacturer;
}
public String getLicensePlate()
{
return licensePlate;
}
public void setLicensePlate(String licensePlate)
{
this.licensePlate = licensePlate;
}
public Integer getSeatCount()
{
return seatCount;
}
public void setSeatCount(Integer seatCount)
{
this.seatCount = seatCount;
}
public String getEngineType()
{
return engineType;
}
public void setEngineType(String engineType)
{
this.engineType = engineType;
}
public Boolean getConvertible()
{
return convertible;
}
public void setConvertible(Boolean convertible)
{
this.convertible = convertible;
}
public Integer getRating()
{
return rating;
}
public void setRating(Integer rating)
{
this.rating = rating;
}
}
CarDTO.java
package com.mytaxi.datatransferobject;
import javax.validation.constraints.NotNull;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.mytaxi.domainvalue.Type;
#JsonInclude(JsonInclude.Include.NON_NULL)
public class CarDTO
{
#JsonIgnore
private Long id;
#NotNull(message = "license plate can not be null!")
private String licensePlate;
#NotNull(message = "cartype can not be null!")
private Type carType;
#NotNull(message = "seatCount can not be null!")
private Integer seatCount;
#NotNull(message = "engineType can not be null!")
private String engineType;
private Boolean convertible;
private CarDTO()
{
}
public CarDTO(Long id, String licensePlate, Type carType, Integer seatCount, String engineType, Boolean convertible)
{
this.id = id;
this.licensePlate = licensePlate;
this.carType = carType;
this.seatCount = seatCount;
this.engineType = engineType;
this.convertible = convertible;
}
public static CarDTOBuilder newBuilder()
{
return new CarDTOBuilder();
}
#JsonProperty
public Long getId()
{
return id;
}
public String getLicensePlate()
{
return licensePlate;
}
public Type getCarType()
{
return carType;
}
public Integer getSeatCount()
{
return seatCount;
}
public String getEngineType()
{
return engineType;
}
public Boolean getConvertible()
{
return convertible;
}
public static class CarDTOBuilder
{
private Long id;
private String licensePlate;
private Type carType;
private Integer seatCount;
private String engineType;
private Boolean convertible;
public CarDTOBuilder setId(Long id)
{
this.id = id;
return this;
}
public CarDTOBuilder licensePlate(String licensePlate)
{
this.licensePlate = licensePlate;
return this;
}
public CarDTOBuilder setLicensePlate(String licensePlate)
{
this.licensePlate = licensePlate;
return this;
}
public CarDTOBuilder setCarType(Type carType)
{
this.carType = carType;
return this;
}
public CarDTOBuilder setSeatCount(Integer seatCount)
{
this.seatCount = seatCount;
return this;
}
public CarDTOBuilder setEngineType(String engineType)
{
this.engineType = engineType;
return this;
}
public CarDTOBuilder setConvertible(Boolean convertible)
{
this.convertible = convertible;
return this;
}
public CarDTO createCarDTO()
{
return new CarDTO(id, licensePlate, carType, seatCount, engineType, convertible);
}
}
}
CarMapper.java
package com.mytaxi.controller.mapper;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import com.mytaxi.datatransferobject.CarDTO;
import com.mytaxi.domainobject.CarDO;
public class CarMapper
{
public static CarDO makeCarDO(CarDTO carDTO)
{
return new CarDO(carDTO.getCarType(), carDTO.getLicensePlate(),
carDTO.getSeatCount(), carDTO.getEngineType(), carDTO.getConvertible());
}
public static CarDTO makeCarDTO(CarDO carDO)
{
CarDTO.CarDTOBuilder carDTOBuilder = CarDTO.newBuilder()
.setId(carDO.getId())
.setCarType(carDO.getManufacturer())
.licensePlate(carDO.getLicensePlate())
.setSeatCount(carDO.getSeatCount())
.setEngineType(carDO.getEngineType())
.setConvertible(carDO.getConvertible());
return carDTOBuilder.createCarDTO();
}
public static List<CarDTO> makeCarDTOList(Collection<CarDO> cars)
{
return cars.stream()
.map(CarMapper::makeCarDTO)
.collect(Collectors.toList());
}
}
CarService.java
package com.mytaxi.service.car;
import java.util.List;
import com.mytaxi.domainobject.CarDO;
import com.mytaxi.domainvalue.Type;
import com.mytaxi.exception.ConstraintsViolationException;
import com.mytaxi.exception.EntityNotFoundException;
public interface CarService
{
CarDO create(CarDO carDO) throws ConstraintsViolationException;
}
DefaultCarService.java
#Override
public CarDO create(CarDO carDO) throws ConstraintsViolationException
{
CarDO car;
try
{
car = carRepository.save(carDO);
}
catch (DataIntegrityViolationException e)
{
LOG.warn("ConstraintsViolationException while creating a driver: {}", carDO, e.getCause());
throw new ConstraintsViolationException(e.getMessage());
}
return car;
}
CarRepository.java
package com.mytaxi.dataaccessobject;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
import com.mytaxi.domainobject.CarDO;
import com.mytaxi.domainvalue.Type;
public interface CarRepository extends CrudRepository<CarDO, Long>
{
List<CarDO> findByIsFunctioning(Boolean isFunctioning);
CarDO findByLicensePlate(String licensePlate);
List<CarDO> findByManufacturer(Type type);
}
When I hit the RESTAPI post service, I get the below exception.
Unique index or primary key violation:
aused by: org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "PRIMARY KEY ON PUBLIC.CAR(ID)"; SQL statement:
insert into car (convertible, engine_type, is_booked, is_functioning, license_plate, manufacturer, rating, seat_count, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?) [23505-197]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:357) ~[h2-1.4.197.jar:1.4.197]
at org.h2.message.DbException.get(DbException.java:179) ~[h2-1.4.197.jar:1.4.197]
at org.h2.message.DbException.get(DbException.java:155) ~[h2-1.4.197.jar:1.4.197]
at org.h2.mvstore.db.MVPrimaryIndex.add(MVPrimaryIndex.java:123) ~[h2-1.4.197.jar:1.4.197]
at org.h2.mvstore.db.MVTable.addRow(MVTable.java:732) ~[h2-1.4.197.jar:1.4.197]
at org.h2.command.dml.Insert.insertRows(Insert.java:182) ~[h2-1.4.197.jar:1.4.197]
at org.h2.command.dml.Insert.update(Insert.java:134) ~[h2-1.4.197.jar:1.4.197]
at org.h2.command.CommandContainer.update(CommandContainer.java:102) ~[h2-1.4.197.jar:1.4.197]
at org.h2.command.Command.executeUpdate(Command.java:261) ~[h2-1.4.197.jar:1.4.197]
at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:199) ~[h2-1.4.197.jar:1.4.197]
at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:153) ~[h2-1.4.197.jar:1.4.197]
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61) ~[HikariCP-2.7.9.jar:na]
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java) ~[HikariCP-2.7.9.jar:na]
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:175) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
... 93 common frames omitted"PRIMARY KEY ON PUBLIC.CAR(ID) :
Any idea what is wrong in the code?
I was encountering the same problem for an #Entity class. My data.sql ids were conflicting with the auto-generated ids from H2.
My solution was to change:
#GeneratedValue(strategy = GenerationType.AUTO)
to
#GeneratedValue(strategy = GenerationType.IDENTITY)
This way I could keep my data.sql file.
The javadoc here indicates that GenerationType.IDENTITY "Indicates that the persistence provider must assign primary keys for the entity using a database identity column."
It was generating the sequence from 1, since there were already 3 values in the database which was inserted manually while initializing the application, modifying the auto generated sequences solved the issue.
#Eenvincible, if you created a data.sql to populate the data, you need to delete those.
The problem is probably given by the fact that you already are initializing data, either through a data.sql file, or CommandLineRunner.
Therefore, if you have
#GeneratedValue(strategy = GenerationType.AUTO)
Spring Data JPA automatically tries to set ID from 1 and then autoincrements of 1 for every new entry. If you already have some entries which start with ID 1 that is the problem (there is a conflict of ids).
You should either remove the data inserted if you want to keep things simple, or you should use other methods for generating the id, for example uuid see here https://thorben-janssen.com/generate-uuids-primary-keys-hibernate/

hibernate & spring, invalid identifier

I have stuck on dealing with DB by using hibernate orm in spring mvc environment.
I have some tables; but I'm not gonna tell you my tables(If you want, I will edit this post)
The problem is that when hibernate runs, it generates sql - I can see the sql by configuring "hbm2_ddl auto" - but the sql has invalid identifier.
select newsreplie0_.news_article# as news6_3_4_, newsreplie0_.reply# as reply1_4_,
newsreplie0_.reply# as reply1_4_3_, newsreplie0_.account_account# as account5_4_3_,
newsreplie0_.content as content4_3_, newsreplie0_.dt as dt4_3_,
newsreplie0_.news_article# as news6_4_3_, newsreplie0_.reply_at as reply4_4_3_,
account1_.account# as account1_0_0_, account1_.email as email0_0_,
account1_.passwd as passwd0_0_, accountpro2_.account# as account1_1_1_,
accountpro2_.nickname as nickname1_1_, accountsec3_.account# as account1_2_2_,
accountsec3_.activate_key as activate2_2_2_, accountsec3_.activated as activated2_2_,
accountsec3_.enabled as enabled2_2_, accountsec3_.login_failed as login5_2_2_
from news_reply newsreplie0_
left outer join
cookingstep.account account1_ on newsreplie0_.account_account#=account1_.account#
left outer join
cookingstep.account_profile accountpro2_ on account1_.account#=accountpro2_.account#
left outer join
cookingstep.account_security accountsec3_ on account1_.account#=accountsec3_.account#
where newsreplie0_.news_article#=9
{FAILED after 4 msec}
The above statement is a sql generated by hibernate. And the error is:
java.sql.SQLSyntaxErrorException:
ORA-00904: "NEWSREPLIE0_"."ACCOUNT_ACCOUNT#": Invalid Identifier
In that exception message, there is a column called "ACCOUNT_ACCOUNT#".
It should be just "ACCOUNT#", not following "ACCOUNT_".
So, how to remove the word ?
EDIT:
Thank you all for your reply. I have asked similar question before.
And I checked out that article, it seems the problem was #JoinColumn annotation missing. Now it works out.
Here is my Entities.
Account.java for user information
package com.musicovery12.cookingstep.persistence.model;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
#Entity
#Table(name="account", catalog="cookingstep", uniqueConstraints= {
#UniqueConstraint(columnNames="email")
})
public class Account implements Serializable{
private static final long serialVersionUID = 1L;
private int accountId;
private String email;
private String password;
private Set<UserRole> userRoles = new HashSet<UserRole>(0);
private AccountProfile profile;
private AccountSecurity security;
private Set<News> newsList;
private Set<NewsReply> newsReplyList;
public Account() {}
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq_account")
#SequenceGenerator(name="seq_account", sequenceName="seq_account", allocationSize=1)
#Column(name="account#", unique=true, nullable=false)
public int getAccountId() {
return accountId;
}
public void setAccountId(int accountId) {
this.accountId = accountId;
}
#Column(name="email", unique=true, nullable=false)
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#Column(name="passwd", nullable=false)
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#OneToMany(mappedBy="pk.account", fetch=FetchType.EAGER, cascade=CascadeType.ALL)
public Set<UserRole> getUserRoles() {
return userRoles;
}
public void setUserRoles(Set<UserRole> userRoles) {
this.userRoles = userRoles;
}
#OneToOne(mappedBy="account", fetch=FetchType.EAGER, cascade=CascadeType.ALL)
public AccountProfile getProfile() {
return profile;
}
public void setProfile(AccountProfile profile) {
this.profile = profile;
}
#OneToOne(mappedBy="account", fetch=FetchType.EAGER, cascade=CascadeType.ALL)
public AccountSecurity getSecurity() {
return security;
}
public void setSecurity(AccountSecurity security) {
this.security = security;
}
#OneToMany(mappedBy="account", fetch=FetchType.LAZY, cascade=CascadeType.ALL)
public Set<News> getNewsList() {
return newsList;
}
public void setNewsList(Set<News> newsList) {
this.newsList = newsList;
}
#OneToMany(mappedBy="account", fetch=FetchType.LAZY, cascade=CascadeType.ALL)
public Set<NewsReply> getNewsReplyList() {
return newsReplyList;
}
public void setNewsReplyList(Set<NewsReply> newsReplyList) {
this.newsReplyList = newsReplyList;
}
}
and NewsReply.java for news community article's reply list.
package com.musicovery12.cookingstep.persistence.model;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
#Entity
#Table(name="news_reply")
public class NewsReply {
private int replyId;
private News news;
private Date date;
private String content;
private Account account;
private int replyAt;
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="gen_seq")
#SequenceGenerator(name="gen_seq", sequenceName="gen_seq", allocationSize=1)
#Column(name="reply#", unique=true, nullable=false)
public int getReplyId() {
return replyId;
}
public void setReplyId(int replyId) {
this.replyId = replyId;
}
#Temporal(TemporalType.DATE)
#Column(name="dt")
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
#Column(name="content", nullable=false)
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
#Column(name="reply_at")
public int getReplyAt() {
return replyAt;
}
public void setReplyAt(int replyAt) {
this.replyAt = replyAt;
}
#ManyToOne
public News getNews() {
return news;
}
public void setNews(News news) {
this.news = news;
}
#ManyToOne
#JoinColumn(name="account#", referencedColumnName="account#")
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
}
in NewsReply.java, there was no JoinColumn annotation to point foreing key column name.
Thank you.
#ManyToOne
#JoinColumn(name="account#", referencedColumnName="account#")
public Account getAccount() {
return account;
}
This is the problem, you tell hibernate the table has a technical name of account# what is not allowed.
What you can do is to force hibernate to use that # by defining
#ManyToOne
#JoinColumn(name="`account#`", referencedColumnName="`account#`")
public Account getAccount() {
return account;
}
But this is bad style and you have to do it on the owning-side too.
Why dont you let hibernate create the entitys for you? He is much more precisly!

Spring boot don't let me create a repository without database

I've created a project on Spring Boot.
I've two providers extending the same Abstract provider, and i load on startup the one i'm interested in via Spring Profile.
One of the providers is based on JPA, the other have his interface implemented where i make calls to webservices.
This is the interface of the provider wich i don't want to use databases:
package net.worldline.mst.metro.ds.core.massilia.provider;
import net.worldline.mst.metro.ds.core.contract.IProductRepository;
import net.worldline.mst.metro.ds.core.massilia.model.MassiliaProduct;
import org.springframework.context.annotation.Profile;
import org.springframework.data.repository.NoRepositoryBean;
#Profile("massilia")
#NoRepositoryBean
public interface MassiliaProductRepository extends IProductRepository<MassiliaProduct,String> {
}
And this is the interface for the provider using database :
package net.worldline.mst.metro.ds.core.local.provider;
import net.worldline.mst.metro.ds.core.contract.IProductRepository;
import net.worldline.mst.metro.ds.core.local.model.Product;
import org.springframework.context.annotation.Profile;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.List;
import org.springframework.stereotype.Repository;
#Profile("local")
#Repository
public interface MonBoProductRepository extends IProductRepository<Product,String> {
#Query("select p.variants from Product p where p.ean = :ean")
List<Product> findVariantByEan(#Param("ean") String ean);
#Query("select p.companions from Product p where p.ean = :ean")
List<Product> findCompanionByEan(#Param("ean") String ean);
}
They extend this interface in common :
package net.worldline.mst.metro.ds.core.contract;
import net.worldline.mst.metro.ds.core.model.AbstractProduct;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.web.bind.annotation.PathVariable;
import java.io.Serializable;
import java.util.List;
import org.springframework.http.HttpEntity;
import org.springframework.web.bind.annotation.PathVariable;
import java.io.Serializable;
import java.util.List;
#NoRepositoryBean
public interface IProductRepository<T extends AbstractProduct,ID extends Serializable> extends CrudRepository<T, ID> {
#RestResource(path = "byEAN")
T findByEan(#Param("ref") Integer ean);
T findProductByEan(#PathVariable ID ean);
List<T> findVariantByEan(#PathVariable ID ean);
List<T> findCompanionByEan(#PathVariable ID ean);
}
The provider wich isn't using database have an implementation, for job reasons, i can't show you the implementation, but it calls inside webservices
Like my providers, i've two models, extending the same abstract class.
One is annoted with #Entity,#Id and co, and i don't want to add this annotations on the other class, because for me, i've precised that i didn't want any database by asking none in the application-${profile}.properties.
This is this Model i used with the bdd :
package net.worldline.mst.metro.ds.core.local.model;
import net.worldline.mst.metro.ds.core.model.AbstractProduct;
import net.worldline.mst.metro.ds.core.model.AbstractProductCharacteristic;
import org.hibernate.validator.constraints.NotEmpty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Profile;
import javax.persistence.*;
import java.util.List;
#Entity
#Table(name = "PRODUCTS")
#Profile("local")
public class Product extends AbstractProduct {
private static final Logger log = LoggerFactory.getLogger(Product.class);
#ManyToMany(
fetch = FetchType.LAZY
)
#JoinTable(
name="products_to_variants",
joinColumns = #JoinColumn(name="productEan"),
inverseJoinColumns = #JoinColumn(name="productEanVariant")
)
private List<Product> variants;
#ManyToMany(
fetch = FetchType.LAZY
)
#JoinTable(
name="products_to_companions",
joinColumns = #JoinColumn(name="productEan"),
inverseJoinColumns = #JoinColumn(name="productEanCompanion")
)
private List<Product> companions;
#Column(name = "accroche")
private String accroche;
#Id
#Column(name = "ean", unique = false)
private String ean;
#Column(name = "descriptif")
private String descriptif;
#Column(name = "libelle")
#NotEmpty
private String libelle;
#Column(name = "oldPrice")
private String oldPrice;
#Column(name = "price")
#NotEmpty
//#Digits(fraction = 0, integer = 10)
private String price;
#Column(name = "stock")
private String stock;
#OneToMany(mappedBy = "ean" )
protected List<ProductCharacteristic> characteristics;
#OneToMany(mappedBy = "product" )
#NotEmpty
protected List<ProductVisual> visuals;
public List<Product> getVariants() {
return variants;
}
public void setVariants(List<Product> variants) {
this.variants = variants;
}
public List<Product> getCompanions() {
return companions;
}
public void setCompanions(List<Product> companions) {
this.companions = companions;
}
#Override
public String getAccroche() {
return accroche;
}
#Override
public void setAccroche(String accroche) {
this.accroche = accroche;
}
#Override
public String getEan() {
return ean;
}
public void setRef(String ean) {
this.ean = ean;
}
#Override
public String getLibelle() {
return libelle;
}
#Override
public void setLibelle(String libelle) {
this.libelle = libelle;
}
#Override
public String getOldPrice() {
return oldPrice;
}
#Override
public void setOldPrice(String oldPrice) {
this.oldPrice = oldPrice;
}
#Override
public String getPrice() {
return price;
}
#Override
public void setPrice(String price) {
this.price = price;
}
#Override
public String getStock() {
return stock;
}
#Override
public void setStock(String stock) {
this.stock = stock;
}
#Override
public List<? extends AbstractProductCharacteristic> getCharacteristics() {
return characteristics;
}
#Override
public List<ProductVisual> getVisuals() {
return visuals;
}
public String getDescriptif() {
return this.descriptif;
}
public void setDescriptif(String descriptif) {
this.descriptif=descriptif;
}
}
This is the model i don't want to use with a database:
package net.worldline.mst.metro.ds.core.massilia.model;
import net.worldline.mst.metro.ds.core.model.AbstractProduct;
import org.springframework.context.annotation.Profile;
import javax.persistence.*;
import java.util.List;
#Profile("massilia")
public class MassiliaProduct extends AbstractProduct {
#Override
public String getEan() { return this.ean; }
#Override
public String getLibelle() { return this.libelle; }
#Override
public String getPrice() { return this.price; }
#Override
public String getAccroche() { return this.accroche; }
#Override
public String getOldPrice() { return oldPrice; }
#Override
public String getStock() { return stock; }
#Override
public String getDescriptif() {
return descriptif;
}
#Override
public List<MassiliaCharacteristic> getCharacteristics() {
return (List<MassiliaCharacteristic>)characteristics;
}
#Override
public List<MassiliaProductVisual> getVisuals() {
return (List<MassiliaProductVisual>)visuals;
}
}
They share this model in common :
package net.worldline.mst.metro.ds.core.model;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.core.Relation;
import java.util.List;
#Relation(value = "product", collectionRelation = "product")
public abstract class AbstractProduct extends ResourceSupport {
protected String ean;
protected String libelle;
protected String accroche;
protected String price;
protected String oldPrice;
protected String stock;
protected String descriptif;
protected List<? extends AbstractProductCharacteristic> characteristics;
protected List<? extends AbstractProductVisual> visuals;
public abstract String getEan();
public abstract String getLibelle();
public abstract String getPrice();
public abstract String getAccroche();
public abstract String getOldPrice();
public abstract String getStock();
public abstract List<? extends AbstractProductCharacteristic> getCharacteristics();
public abstract List<? extends AbstractProductVisual> getVisuals();
public abstract String getDescriptif();
public void setEan(String ean) {
this.ean = ean;
}
public void setLibelle(String libelle) {
this.libelle = libelle;
}
public void setPrice(String price) {
this.price = price;
}
public void setAccroche(String accroche) {
this.accroche = accroche;
}
public void setOldPrice(String oldPrice) {
this.oldPrice = oldPrice;
}
public void setStock(String stock) {
this.stock = stock;
}
public void setCharacteristics(List<? extends AbstractProductCharacteristic> characteristics) {
this.characteristics = characteristics;
}
public void setVisuals(List<? extends AbstractProductVisual> visuals) {
this.visuals = visuals;
}
public void setDescriptif(String descriptif) {
this.descriptif = descriptif;
}
}
In the application-${profile}.properties, i precise :
spring.datasource.platform = hsqldb for the jpa instance.
spring.datasource.platform = none for the instance where i call my webservices.
My problem is simple : i was hoping spring letting me do what i want by implementing the repository, but when i launch my server, spring say that my objects are not managed, so if i don't add #Entity to my model, it doesn't want to run.
So why Spring data looks like it loads JPA repository by default ?
It was a human error in fact.
I'v forgotten a spring.datasource.platform = hsqldb in my application.properties file.
I wasn't looking at it cause i'm using spring profiles so i was looking at my application-massilia.properties wich contains spring.datasource.platform = none and is listened now cause i've deleted the duplicate in the other file.

Resources