Hibernate custom sequence generator - Table doesn't exist - spring-boot

I'm using a custom class to generate id:
public class StringPrefixedSequenceIdGenerator extends SequenceStyleGenerator
Also using this class on entity attribute:
#Id
#GenericGenerator(name = "pipeline_seq_generator", strategy = "com.model.StringPrefixedSequenceIdGenerator", parameters = {
#Parameter(name = StringPrefixedSequenceIdGenerator.INCREMENT_PARAM, value = "50") })
#GeneratedValue(generator = "pipeline_seq_generator", strategy = GenerationType.SEQUENCE)
#Column(name = "pipeline_id", unique = true, nullable = false, length = 100)
public String getPipelineId() {
return this.pipelineId;
}
The problem is that hibernate still try to get the sequence from database:
select next_val as id_val from pipeline_seq_generator for update
Error: java.sql.SQLSyntaxErrorException: Table 'table.pipeline_seq_generator' doesn't exist
EDIT: The #Override generate method is causing hibernate to call sequence from database when I pass super.generate(session,object) as a parameter in my method :
#Override
public Serializable generate(SharedSessionContractImplementor session,
Object object) throws HibernateException {
return String.format(format, LocalDate.now(), super.generate(session, object));
}

I changed the implementation of generate method to not use the super.generate(session, object):
#Override
public Serializable generate(SharedSessionContractImplementor session,
Object object) throws HibernateException {
LocalTime localTime = LocalTime.now();
return prefix + String.format(format, LocalDate.now()) + localTime.getHour() + localTime.getMinute() + localTime.getSecond();
}
In this model I'm only using my implementation without use sequence database.

In
public void configure(Type type, Properties properties,
ServiceRegistry serviceRegistry) throws MappingException {
// ignore the (String) Type input parameter and use a new LongType()
super.configure(new LongType(), properties, serviceRegistry);
String Types can not be generated by a sequence in hibernate (liquibase)
after this you can just use:
String toString = super.generate(session, object).toString();
in the generate method and add a prefix .

Related

Spring specification search inside JSON array of String

I am using Postgres version 12 database and ORM Hibernate mapping, and Assuming that i have next Entity:
#Entity
public class MyEntity {
#Type(type = "json")
#Column(name = "names", columnDefinition = "json")
private List<String> names;
// Getters and Setters
}
So the data will be persisted like that inside the table column (names):
["Sara", "Anton", "Lars"]
and i want to add a specification to search on that json from postgres database, i tried next one but it didn't work :(
private static Specification<MyEntity> withNames(String name) {
return (root, query, builder) -> {
Expression<String> function = builder.function("json_array_elements", String.class, root.get("names"));
return StringUtils.isBlank(name) ? builder.conjunction() : builder.like(function, name + "%");
};
}
Any suggestions of how to get it work?

JHipster - Insert in the database with the GET method

I have to create an application with Jhipster but i never use it before.
When a user send a GET request to the address http://localhost:8080/api/newmesure/{mac-address}/{value}
I want to insert a new mesure in my database.
First i created 3 entity "Plantes", "Capteurs" and "Mesures" with this format :
Image here : https://i.stack.imgur.com/zJqia.png (I'm not allowed to post)
I activated the JPA Filtering to create a #Query to insert data in my database but i read that was not possible.
In /src/main/java/com/mycompany/myapp/web/rest/MesuresRessources.java :
/**
* REST controller for managing {#link com.mycompany.myapp.domain.Mesures}.
*/
#RestController
#RequestMapping("/api")
public class MesuresResource {
private final Logger log = LoggerFactory.getLogger(MesuresResource.class);
private static final String ENTITY_NAME = "mesures";
#Value("${jhipster.clientApp.name}")
private String applicationName;
private final MesuresService mesuresService;
private final MesuresQueryService mesuresQueryService;
public MesuresResource(MesuresService mesuresService, MesuresQueryService mesuresQueryService) {
this.mesuresService = mesuresService;
this.mesuresQueryService = mesuresQueryService;
}
#GetMapping("/newMesure/{mac}/{value}")
public String newMesure(#PathVariable String mac,#PathVariable int value) {
log.debug("Adresse MAC : "+mac);
log.debug("Valeur : "+value);
#Query("SELECT valeur FROM Mesures WHERE id = 1") //not working
Mesures getValeur(); //not working
return "Mesure ajoutée";
}
}
In /src/main/java/com/mycompany/myapp/domain/Mesures.java :
/**
* A Mesures.
*/
#Entity
#Table(name = "mesures")
public class Mesures implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "valeur")
private Integer valeur;
#ManyToOne(optional = false)
#NotNull
#JsonIgnoreProperties("macs")
private Capteurs mac;
// jhipster-needle-entity-add-field - JHipster will add fields here, do not remove
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getValeur() {
return valeur;
}
public Mesures valeur(Integer valeur) {
this.valeur = valeur;
return this;
}
public void setValeur(Integer valeur) {
this.valeur = valeur;
}
public Capteurs getMac() {
return mac;
}
public Mesures mac(Capteurs capteurs) {
this.mac = capteurs;
return this;
}
public void setMac(Capteurs capteurs) {
this.mac = capteurs;
}
// jhipster-needle-entity-add-getters-setters - JHipster will add getters and setters here, do not remove
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Mesures)) {
return false;
}
return id != null && id.equals(((Mesures) o).id);
}
#Override
public int hashCode() {
return 31;
}
#Override
public String toString() {
return "Mesures{" +
"id=" + getId() +
", valeur=" + getValeur() +
"}";
}
}
Louan
Learning java with JHipster is probably not a wise idea, it uses a very rich technology stack which might lose you unless you invest enough time to learn the basics.
There are many things wrong in your code and approach:
You can't use #Query annotation inside the body of method a of your REST controller, it must be used in your #Repository interface, this code can't compile. See https://www.baeldung.com/spring-data-jpa-query for a quick introduction
JPA filtering is not related to inserting into database
In HTTP/REST, GET method is supposed to be idempotent. For making changes in your database you should use POST or PUT methods. See What is idempotency in HTTP methods?
Your entity naming convention is not consistent: use singular for entity classes because each entity object represents one single instance of Mesure. Here you have Plantes (plural), Capteur (singular) and Mesures (plural). For table names, JHipster uses singular but plural is quite common too because a table holds many rows. Of course, this is just a convention and you or your team may decide to apply another (like a prefix for table names) but the key point is to be consistent.

Hibernate -validator group sequence provider getDefaultSequenceProvider gets null as input

I am using the hibernate validator group sequence and want to execute the groups in a sequence based on business rules. But the input to the groupSequenceProvider for its getValidationGroups is always null, and hence custom sequence never gets added.
My request object:
#GroupSequenceProvider(BeanSequenceProvider.class)
public class MyBean {
#NotEmpty
private String name;
#NotNull
private MyType type;
#NotEmpty(groups = Special.class)
private String lastName;
// Getters and setters
}
Enum type:
public enum MyType {
FIRST, SECOND
}
My custom sequence provider:
public class BeanSequenceProvider implements DefaultGroupSequenceProvider<MyBean> {
#Override
public List<Class<?>> getValidationGroups(MyBean object) {
final List<Class<?>> classes = new ArrayList<>();
classes.add(MyBean.class);
if (object != null && object.getType() == MyType.SECOND) {
classes.add(Special.class);
}
return classes;
}
}
Group annotation:
public interface Special {
}
When I execute the above code, I get the input MyBean object as null and cannot add the custom sequence. What am I missing? I am using hibernate-validator version as 5.4.1.Final

Spring does not inject SessionFactory when calling CustomValidator second Time

i am developing a application using spring and hibernate. i have created a custom validator for for checking duplicate value in the database for that i need to inject hibernate SessionFactory in the CustomValidator. it works fine for on a single field but when i apply it on two or more field i get a NullPointerException it seems like spring does not inject the SessionFactory while calling validator second time.
here is code of entity class
public class CenterRegistration implements Serializable {
#Column(unique=true)
#UniqueKey(message="Email Id already exist please choose another Email Id ", table = "CenterRegistration", column = "email")
private String email;
#UniqueKey(message="UserName already exist please choose another username", table = "CenterRegistration", column = "userName")
#Column(unique = true)
private String userName;
And here is code of customvalidator implementing class
public class UserNameConstraintValidator implements
ConstraintValidator<UniqueKey, String> {
#Inject
private SessionFactory sessionFactory;
public boolean isValid(String value, ConstraintValidatorContext context) {
System.out.println("in is valid value=" + value + " " + sessionFactory);
if (sessionFactory == null) {
return true;
}
Session session = sessionFactory.openSession();
it works fine when i apply this validator on a single field on my entity but when applying on second spring injects null into the sessionfactory.
if (sessionFactory == null) {
return true;
}
i have used these just to avoid NullPointerException.

How to write a search class to accept any type of parameter?

I'm using spring mvc and I created the CRUD functionality. But I want to create a search function that will allow me to find a user by any parameter (variable) as 'userid' or 'username' or 'lastname' or 'social security number' or whatever.
My userid is an integer type.
How can I do that? What is the SQL query for that?
How can I check if the input is integer or string and then go through the database by the given parameter and search for the user?
If you are using Hibernate for data access you can easily create universal finder using criteria API:
Abstract DAO class:
public abstract class AbstractHibernateDAO<T> {
private static final String PARAM_VALUE_PARAMETER = "paramValue";
private final Class<T> clazz;
#Autowired
private SessionFactory sessionFactory;
public AbstractHibernateDAO(Class<T> clazz) {
this.clazz = clazz;
}
public T findOne(String paramName, Object paramValue) {
Session session = sessionFactory.getCurrentSession();
#SuppressWarnings("unchecked")
T fetchedObject = (T) session.createCriteria(clazz).add(Restrictions.eq(paramName, paramValue)).uniqueResult();
return fetchedObject;
}
// Other CRUD methods.
}
Concrete DAO class for entity:
#Repository
#Transactional
public class ProductHibernateDAO extends AbstractHibernateDAO<Product> {
public ProductHibernateDAO() {
super(Product.class);
}
}
Or if you prefer to use HQL instead of Criteria API you can rewrite search method as:
public T findOne(String paramName, Object paramValue) {
Session session = sessionFactory.getCurrentSession();
StringBuilder queryText = new StringBuilder();
queryText.append("from ");
queryText.append(clazz.getSimpleName());
queryText.append(" where ");
queryText.append(paramName);
queryText.append("=:");
queryText.append(PARAM_VALUE_PARAMETER);
#SuppressWarnings("unchecked")
T fetchedObject = (T) session.createQuery(queryText.toString()).setParameter(PARAM_VALUE_PARAMETER, paramValue).uniqueResult();
return fetchedObject;
}
In this article you can find very good description how to create generic DAO with hibernate (Or if you prefer JPA there are also described how to do this with JPA).
Or if you prefer to use JDBC for data access I recommend you to look at Spring's JdbcTemplate. It simplifies development a lot. Here how you can implement universal finder using JdbcTemplate:
#Repository
#Transactional
public class ProductJDBCDAO implements DAO<Product> {
private static final String TABLE_NAME = "product";
#Autowired
private JdbcTemplate jdbcTemplate;
public Product findOne(String paramName, Object paramValue) {
RowMapper<Product> rowMapper = new RowMapper<Product>(){
public Product mapRow(ResultSet rs, int rowNum) throws SQLException {
long productId = rs.getLong("product_id");
// Other properties
Product product = new Product(...);
return product;
}
};
StringBuilder queryText = new StringBuilder();
queryText.append("select * from ");
queryText.append(TABLE_NAME);
queryText.append(" where ");
queryText.append(paramName);
queryText.append("=?");
Product fetchedObject = jdbcTemplate.queryForObject(queryText.toString(), rowMapper, paramValue);
return fetchedObject;
}
// Other CRUD methods
}
Ass you can see in all examples you don't need explicitly specify parameter type, you just add it as Object parameter.
If you will work with direct JDBC in such case I recommend you to use PreparedStatement and it's setObject(..) method. Query text will be similar to shown in the example with JdbcTemplate.

Resources