Spring Bean Validation with Hibernate: validation not happening on update - spring

I have a class defined as follows:
import org.hibernate.validator.constraints.NotBlank;
public class Game {
#GeneratedValue(strategy = GenerationType.AUTO)
#Id
#Column(name = "id")
Long id;
#NotBlank
#Column(name = "title")
String title;
...
However, when I execute the following test, no validation exception is thrown:
#Test(expected = ConstraintViolationException.class)
public void thatExistingGameGivenBlankTitleCannotBeSaved(){
Game game = new Game("SimCity 2000");
gameDAO.save(game);
game.setTitle(" "); //game.setTitle(null) doesn't work either
gameDAO.save(game);
}
How can I make the validator trigger when saving an already persisted object? Preferably through Java configuration.
My validation dependencies:
<!-- validation -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.0.Final</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator-cdi</artifactId>
<version>5.1.0.Final</version>
</dependency>

Your JPA implementation has to integrate bean validation. If you're using Hibernate this will happen automatically by putting the validation provider in the class path. If not read 10.1.3. JPA. Given your tags I assume you're using JPA/Hibernate and it should work.
I don't know what gameDAO.save() is calling on your JPA implementation. Hibernate's integration is event based. If your save() is none of these events there will be no validation by default:
PreInsertEvent
PreUpdateEvent
PreDeleteEvent

Related

Spring Boot Validation is not working with javax.validation

I am working on a Spring Boot project and I am currently trying to implement validation. For example, I have the following class:
package abcdef.mypackage
import java.util.*
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.Id
import javax.validation.constraints.Email
import javax.validation.constraints.NotBlank
#Entity
class User (
#Id
#GeneratedValue
var id: Long,
#Column(name="username", unique = true, nullable = false)
#NotBlank
var username: String,
#Column(name="password", unique = false, nullable = false)
var password: String,
#Column(name="firstname", unique = false, nullable = false)
#NotBlank
var firstname: String,
#Column(name="lastname", unique = false, nullable = false)
#NotBlank
var lastname: String,
#Column(name = "birthdate", unique = false, nullable = true)
var birthdate: Date? = null,
#Column(name="email", unique = true, nullable = false)
#Email
var email: String,
#Column(name="phone", unique = true, nullable = false)
var phone: String,
)
You can see, that I have annotated all fields with the validations I want to have. Incoming requests are handled by the following controller class:
package abcdef.mypackage
import org.springframework.http.ResponseEntity
import org.springframework.validation.BindingResult
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.*
import org.springframework.web.server.ResponseStatusException
import javax.validation.Valid
#RestController
#RequestMapping("/api/v1/users/")
#Validated
class UserResource(val service: UserService) {
#PostMapping("/register")
#Validated
fun post(#Valid #RequestBody user: User, result: BindingResult) : ResponseEntity<Unit> {
if (result.hasErrors()) {
return ResponseEntity.badRequest().build()
}
try {
service.post(user)
} catch (e: Exception) {
return ResponseEntity.badRequest().build()
}
return ResponseEntity.ok().build()
}
}
When I now make a request with for example a blank username value, Spring Boot still accepts it and stores into the database. I have found some questions (and answers) on StackOverflow about missing dependencies, but I included all of those. You can take a look at my dependecies here:
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
</dependencies>
I have no Idea what to do to get this validation working... I cannot see any issue in my dependencies. I also tried some variations with the usage of #Valid and #Validated but nothing worked for me.
I hope somebody sees my mistake. Thanks a lot!
Example: recommend data class + #field:NotBlank and not need #Validated

Spring data jpa repository findBy returning null even if data present in DB

I am using spring data JPA, facing issue as result is always coming NULL even if record present into DB.
I tried debugging spring code and checked whether statement created correctly or not. Statement is created correctly and parameter is also populated correctly.
Configuration: -
Spring-boot = 2.0.5.RELEASE
Oracle DB = Oracle Database 11g Release 11.2.0.2.0 - 64bit
POM
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc7</artifactId>
<version>12.1.0</version>
</dependency>
</dependencies>
Entity class:
#Entity()
public class User {
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "user_Sequence")
#SequenceGenerator(name = "user_Sequence", sequenceName = "USER_SEQ")
private Long id;
#Column(unique=true)
private String userName;
private String password;
//getter & setter
Repository class
#Repository
public interface UserRepository extends
org.springframework.data.repository.CrudRepository<User, Long>{
User findByUserName(String userName);
User save(User user);
}
Service class
#Service("loginService")
public class LoginService implements ILoginService {
#Autowired
UserRepository userRepository;
#Override
public boolean isValidUser(String userName, String password) {
User user = userRepository.findByUserName(userName);
if(user != null && user.getUserName().equals(userName) && user.equals(password)){
return true;
} else {
return false;
}
}
}
Debug Screenshot : -
Debug Screenshot parameter value is "admin" and SQL formed
SQL Formed : -
select user0_."id" as id1_2_, user0_."password" as password2_2_, user0_."user_name" as user_name3_2_ from "user" user0_ where user0_."user_name"=?
If I run same query in DB, result is : -
Result Screenshot
Since you are not using your column name as your field names it needs to know what to map to in your entity.
Change your field to either be user_name or change:
#Column(unique=true)
private String userName;
to
#Column(name="user_name", unique=true)
private String userName;
thus it will be able to know what column it references;
https://www.concretepage.com/spring-5/spring-data-crudrepository-example
use findByNameEqualsAndStatus in Repository
Below are things that work for me. I am using Oracle 19C with org.hibernate.dialect.Oracle12cDialect.
grant all on <schema>.<table> to <user>;
grant all on <schema>.<sequence> to <user>;

"IllegalArgumentException: At least one JPA metamodel must be present" - when trying to connect application both to mongo and sql

We have a Spring application that connects with no problems to a MongoDB, with #Autowire and all the rest.
Now we also need the app to connect also to an SQL database.
So we crated an #entity class:
#Entity(name = "SqlCarRecord")
#Table(name = "Cars")
final public class SqlCarRecord {
#Id #GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "name", nullable = false)
private String name;
....
And a #repository interface:
#Repository
public interface SqlCarsRepository extends JpaRepository<SqlCarRecord, Long> {
...
And a #Configuraion class like the example here https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-part-one-configuration/
And in the applicationContext we added
<jpa:repositories base-package="path.to.interface.package" />
In the pom.xml we already have
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.5.RELEASE</version>
</dependency>
and we added:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.0.0.M3</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<version>2.1.0</version>
</dependency>
<!-- DataSource (HikariCP) -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>2.6.2</version>
</dependency>
<!-- JPA Provider (Hibernate) -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.2.10.Final</version>
</dependency>
<!-- Spring Data JPA -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.11.6.RELEASE</version>
</dependency>
<!-- adding this to avoid "java.lang.NoClassDefFoundError: org/w3c/dom/ElementTraversal" -->
<dependency>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.4.01</version>
</dependency>
<!-- adding this to avoid "ClassNotFoundException: org.springframework.data.util.CloseableIterator" -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>1.13.6.RELEASE</version>
</dependency>
And in the #Service class we added:
....
#Autowired
private SqlCarsRepository carsRepository;
The project is built successfully, but when we try to run it, we get this error:
Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean
with name 'jpaMappingContext': Invocation of init method failed; nested
exception is java.lang.IllegalArgumentException: At least one JPA metamodel
must be present!
Some of the things We tried:
change the different versions of spring in the pom,
we tried to comment some of them,
we tried to change the interface to extend CrudRepository,
tried to add an empty constructor to the entity and some other things
with no luck.
Will appriciate help.
Thanks in advance.
I solved the same error message by changing the #SpringBootApplication annotation to this:
#SpringBootApplication(exclude = {JndiConnectionFactoryAutoConfiguration.class,DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,JpaRepositoriesAutoConfiguration.class,DataSourceTransactionManagerAutoConfiguration.class})
If you are using the #EnableAutoConfiguration directly, try this:
#EnableAutoConfiguration(exclude = {JndiConnectionFactoryAutoConfiguration.class,DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,JpaRepositoriesAutoConfiguration.class,DataSourceTransactionManagerAutoConfiguration.class})
It seems that the root problem is that the Spring Boot is trying to add something that is already on the classpath.
Most of answer taken from https://stackoverflow.com/a/30597861/7470360

Spring data JPA and Geometry type

I am developing an application that will run on both MySql and MS SQL.
I have a field that is "geometry" type for spatial.
By using:
#Column(columnDefinition = "geometry")
private Point geometry;
(point is org.springframework.data.geo.Point)
Hibernate creates the field properly (hbm2ddl).
But inserting any point does not work.
I get : Data truncation: Cannot get geometry object from data you send to the GEOMETRY field
I use spring-boot-jpa-starter.. and not direct hibernate.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-spatial</artifactId>
<version>5.2.2.Final</version>
</dependency>
Regards,
Ido
Hello I have successfully mapped a point in JPA. Here's what I did:
I have this on Maven:
<dependency>
<groupId>com.vividsolutions</groupId>
<artifactId>jts</artifactId>
<version>1.13</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-spatial</artifactId>
<version>5.2.5.Final</version>
</dependency>
I have this on my entity:
#Column(name = "locationpoint", columnDefinition = "POINT")
private Point locationpoint;
I have this on my application.properties:
# needed for Location domain class
spring.jpa.properties.hibernate.dialect=org.hibernate.spatial.dialect.mysql.MySQL56InnoDBSpatialDialect
I can get the value using this:
locationRepository.findOne((long) 1).getLocationpoint().getX();
locationRepository.findOne((long) 1).getLocationpoint().getY();
I based my solution from here Matti Tahvonen's example:
https://github.com/mstahv/spring-boot-spatial-example
Hope this helps.

What is the work around for Hibernate 4 persistence support for org.joda.time.contrib.hibernate.PersistentDateTime

Hi All I am new to Spring and am building application using the following dependencies
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time-hibernate</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.1.7.Final</version>
</dependency>
<spring.framework.version>3.1.2.RELEASE</spring.framework.version>
I am not able to persist the objects with fields with datatype DateTime from the class org.joda.time.contrib.hibernate.PersistentDateTime.
#Column(name = "LAST_MODIFIED_DATE")
#Type(type = "org.joda.time.contrib.hibernate.PersistentDateTime")
public DateTime getLastModifiedDate() {
return lastModifiedDate;
}
Can anybody suggest how to use the joda DateTime.
I had been trying this for entire day finally got the solution as the following. org.joda.time.contrib.hibernate.PersistentDateTime class persistence is not supported by higher versions of hibernate. Rather we use some very specific libraries like the
<dependency>
<groupId> org.jadira.usertype </groupId>
<artifactId> usertype.core </artifactId>
<version> 3.0.0.CR3 </version>
</dependency>
This is how we can persist the data in the database for audit purpose.
#Column(name = "CREATED_DATE")
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
public DateTime getCreatedDate() {
return createdDate;
}

Resources