I use the date validaton using the #Future annotation.
#NotNull
#DateTimeFormat(pattern="yyyy-MM-dd")
#Column(name = "FROM")
#Temporal(TemporalType.DATE)
#Future
private Date from;
#NotNull
#Column(name = "FOO")
private String foo;
I perform CRUD operations using Rest API. The requirement is the from date will be in future - after the entity is being created (today). However, the time changes and in case of changing the field foo using ex. PUT method, the validation won't pass.
#PutMapping(value = "/{id}")
public ResponseEntity<?> put(
#Valid #RequestBody MyEntity myEntity,
#PathVariable("id") int id)
{
... update entity based on id
}
When I call this method in the far future (after the from value persisted), the validation doesn't let me perform the operation, because the field from is no more valid.
There is a simple in-built solution to trigger a certain validation only on create event?
I have been thinking over creating the own cross-field validation through annotation, however I am not able to determine the creation based on other fields.
You can use Grouping Constraints, to restrict which validation set to use for: pre-persist, pre-update, pre-remove and ddl(For database schema).
So to validate from field just for persist operation and ignore it for put(update), you may:
Add an interface e.g. GroupFuture:
package com.example.entity;
public interface GroupFuture {}
In your MyEntity, I think you should also add #NotNull constraint as #Future consider null as valid value:
//...
//Maybe #NotNull
#Future(groups = GroupFuture.class)
private Date from;
//...
Finally, if you've configured hibernate using:
persistence.xml, add this line in the persistence-unit setting:
<property name="javax.persistence.validation.group.pre-persist" value="javax.validation.groups.Default, com.example.GroupFuture">
Programmatically:
// If you're using pure hibernate
Configuration configuration = new Configuration().setProperty("javax.persistence.validation.group.pre-persist", javax.validation.groups.Default, com.example.GroupFuture);
`
// If you're using JPA/hibernate
entityManagerFactory.getJpaPropertyMap().put("javax.persistence.validation.group.pre-persist", javax.validation.groups.Default, com.example.GroupFuture);
Useful reading(even it's for hibernate 3.6): Chapter 23. Additional modules
Related
I have a JpaRepository persisting newly created entity in Spring MVC app. This entity looks like this (very simplified):
#Entity
public class Translation {
.....
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#ManyToOne(fetch = FetchType.LAZY)
private Version version;
....
}
and Version entity:
#Entity
public class Version {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private long id;
#Column(name = "name")
private String name;
#Column(name = "version_code")
private long code;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "version", cascade = {CascadeType.ALL}, orphanRemoval = true)
private Set<Translation> translations;
}
I create a translation object like this
TranslationDTO t = new TranslationDTO();
t.setText(translationText);
ClientVersionDTO version = new ClientVersionDTO();
version.setId(11);
t.setVersion(version);
where 11 is a version that exists in the database already from the very beginning. Please notice that I do not set values for name and code of ClientVersionDTO.
Then I have a service that persists new object (I use dozer library to convert DTO to entities)
#Service
#Transactional
public class TranslationsServiceImpl implements TranslationsService {
#Override
public Long create(TranslationDTO translationDTO) {
Translation translation = translationsConverter.unconvert(translationDTO);
Translation t = translationRepository.saveAndFlush(translation);
Translation t2 = translationRepository.findOne(t.getId());
// !!!! t2.getVersion() returns version where no values are set to 'code' and 'name'
return t2.getId();
}
}
Please notice my comment "t2.getVersion() returns version where no values are set to 'code' and 'name'" - I was expecting so that when I fetch the data from the database, I would get a Version object right from the database with code and name values set. However they are not set. So basically what I get as a t2.getVersion() object is the same object as in input argument translationDTO.getVersion(). How can they I re-invalidate the Version object?
UPDATE tried moving #Transactional to JpaRepository, but still the same result.
If you are using Hibernate, this is the expected result. When you call translationRepository.saveAndFlush(translation) and translationRepository.findOne(t.getId()) one after the other, they hit the same Hibernate session which maintains a cache of all objects that it has worked on. Therefore, the second call simply returns the object passed to the first. There is nothing in those two lines that would have forced Hibernate to fire a SELECT query on the database for the Version entity.
Now, the JPA spec does have a refresh method on the EntityManager interface. Unfortunately, Spring Data JPA does not expose this method using its JpaRepository interface. If this method was available, you could have done t = translationRepository.saveAndFlush(translation) and then versionRepository.refresh(t.getVersion()) to force the JPA provider to synchronize the version entity with the database.
Implementing this method is not difficult. Just extend SimpleJpaRepository class from Spring Data JPA and implement the method yourself. For details see adding custom behaviour to all Spring Data JPA repositories.
An alternate would be to load the version entity as versionRepository.findOne(version.getId()) before setting it on the translation. Since you can hard-code version id in your code, your versions seem to be static. You can therefore mark your Version entity as #Immutable and #Cacheable (the former is a Hibernate-specific annotation). That way, versionRepository.findOne(version.getId()) should not hit the database every time it is called.
I have the following bean;
public class Customer {
#NotNull(groups = New.class)
private String id;
#Valid
private List<CustomerDetail> detailList;
}
As you see, I cascade validation down to each CustomerDetail in detailList by annotating the field with #Valid, but I wish to propagate the validation with a hard-coded group, is that possible? Whatever group is supplied for validation, I wish a fixed group, namely New to be active in validation of detailList.
This is due to my conflicting requirements, one wishes to treat details as a sub-resource of Customer therefore I need full validation on it all the time when it is validated within a customer pojo. Another requirement is to treat each detail as a separate resource, therefore I need to do patch for some fields, so when it is validated separately, different groups can be applied.
public class CustomerDetail {
#NotNull(groups = New.class)
private String desc;
private String remark;
}
So when it is any sort of operation for Customer, every CustomerDetail in customerList should use New group, even if Customer does not necessarily use that group for validation.
In a way, I want to do this;
public class Customer {
#NotNull(groups = New.class)
private String id;
#Validated(New.class)
private List<CustomerDetail> detailList;
}
But I was unable to find such a feature, I wanted to do this to evade creating multiple groups, which was deemed confusing.
You need to introduce your own annotation to have class level constraints. Create a custom annotation with own validation logic implemented in the validator.
See the chapter 6.2. Class-level constraints of the doc
Or see the example
I have a scenario where I have 2 labels that need to be configured. The names of the labels are 'Out Date' and 'In Date'. I only have one field in the database called 'Date'. Whether it is 'Out' or 'In' is decided at the runtime by the value of an Enum 'Scenario'. However, I need to actually show the user Out Date&In Date so that he can select 1 or both of them. I heard that calculated field concept it JPA will assist in this. Is this true or is there some other way that I can achieve this. Below is some sample code.
Date
#Override
#Convert("DateTimeConverter")
#Column(name = "DATE")
public DateTime getDate() {
return date;
}
Scenario
#Override
#Convert("EnumConverter")
#Column(name = "SCENARIO")
public Scenario getScenario() {
return scenario;
}
Scenario is any enum with the values OUT(1),IN(2)
There are no calculated properties in JPA.
You can use #Transient annotation to create properties that are not persisted but calculated based on other fields:
#Transient
public DateTime getInDate() {
if (scenario == Scenario.IN) {
return date;
}
return null;
}
#Transient
public DateTime getOutDate() {
if (scenario == Scenario.OUT) {
return date;
}
return null;
}
Alternatively, if you are using Hibernate you can use proprietary annotation #Formula:
#Formula("case when SCENARIO = 2 then DATE else NULL end")
#Convert("DateTimeConverter")
private DateTime inDate;
#Formula("case when SCENARIO = 1 then DATE else NULL end")
#Convert("DateTimeConverter")
private DateTime outDate;
I prefer the first option because:
it is easier to test with unit tests
it is easier to use the entity in unit tests
it does not require proprietary extensions
generally there might be some problems with portability of SQL, although in this problem case when is SQL 92 compatible so it does not apply here
The only problem I can is is that in simplest approach is that we abandon encapsulation by exposing to clients internals of the entity (scenario and date properties). But you can always hide these properties with accessor protected, JPA will still handle that.
To compute properties within JPA entities, you can use JPA callbacks.
See this Hibernate JPA Callbacks documentation. (Note: JPA callbacks are not specific to hibernate, it's part of latest JPA 2.1 specification).
And also this OpenJpa JPA Calbacks one.
Following entity life-cycle categories have a Pre and Post event which can be intercepted by the entity manager to invoke methods:
Persist -> #PrePersist, #PostPersist
Remove -> #PreRemove, #PostRemove
Update -> #PreUpdate, #PostUpdate
Load -> #PostLoad (No Pre for this ...)
So let's say you want to compute a complexLabel label from two persisted entity fields label1 and label2 in an entity titled MyEntity:
#Entity
public class MyEntity {
private String label1;
private String label2;
#Transient
private String complexLabel;
#PostLoad
#PostUpdate // See EDIT
// ...
public void computeComplexLabel(){
complexLabel = label1 + "::" + label2;
}
}
As #Dawid wrote, you have to annotate complexLabel with #Transient in order to make them ignored by persistence. If you don't do this, persistence fails because there is no such column in MyEntity corresponding table.
With #PostLoad annotation, computeComplexLabel() method is called by entity manager just after the loading of any instance of MyEntity from persistence.
Thus, #PostLoad annotated method is best suited to put your post loading entity properties enhancement code.
Bellow is an extract from JPA 2.1 specification about PostLoad:
The PostLoad method for an entity is invoked after the entity has been
loaded into the current persistence context from the database or
after the refresh operation has been applied to it. The PostLoad
method is invoked before a query result is returned or accessed or
before an association is traversed.
EDIT
As pointed out by #Dawid, you could also use #PostUpdate in case you want to compute this transient field just after the entity update, and use other callbacks when needed.
I have an entity object similar to the following
#Document(collection = "job")
public class Job {
#Id
private String id;
private JobStatus status;
#NotBlank
private String term;
...standard getters/setters
}
I have a controller something like this:
#RequestMapping(method = RequestMethod.POST)
public ResponseEntity<Job> createJob(#RequestBody #Valid Job job) {
...store the new job in the database
}
The Job.status property is set by the code before storing to the database. Any "status" property included in the request body to the createJob method is ignored.
I would like to validate that Job.status is not null when the job is written to the database, but users must not be required to include a status in the request body. If I annotate the Job.status property with #NotNull, the validation of the request body fails unless I include "status".
How do I validate the status field only when persisting to data store and not as part of the request body?
You're trying to use the database entity as a UI entity with different validation rules. You have options:
Use different classes for the UI and the DB
Create a custom JSR-303 validator for your not null which you somehow avoid applying when you validate in the UI layer
Put the constraint for not null in the database itself, rather than hibernate/JPA and handle the constraint exception
I know it is not new question in this forum but I am very confused what should i do.
Problem: I am developing one application with spring mvc + hibernate. For server side validation I am using #valid annotation in controller and #null and #notNull annotation in my bean.
e.g
public class User implements Serializable {
private static final long serialVersionUID = 2158419746939747203L;
#Id
#Column(name="USER_ID")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private long userId;
#Column(name="USERNAME", unique = true)
#NotEmpty #NotNull #Size(min=6, max=20)
private String username;
#Column(name="PASSWORD")
#NotEmpty #NotNull #Size(min=6, max=20)
private String password;
This validation is happening fine and data is also saving in DB.
But I want to validate unique constraint,referential integrity and other constraint using annotation without any validator class.
Is it possible? if no, then what is best and easiest way to to do it(less coding)? I will appreciate if framework will do it for me.
Saurabh,
For unique constraint in table,
#Id
You will be able to enforce referential integrity via hibernate annotations as well
eg.
#OneToOne(mappedBy = "foo")
Here is an example post
Referential integrity with One to One using hibernate
Here is a very detailed tutorial also exploring the same:
http://www.journaldev.com/2882/hibernate-tutorial-for-beginners-using-xml-annotations-and-property-configurations
You could write a "CustomUniqueConstraintValidator" kinda like mentioned in
http://www.journaldev.com/2668/spring-mvc-form-validation-example-using-annotation-and-custom-validator-implementation
You can also pass in paramters from the annotation to the custom validator.
eg.
#CustomValidDate("columnName")
To make a generic class that applies for any field /column
1. YOu can write a generic custom validator
2. use annotaiton parameters (on each class attribute) to pass in the table name and column name.
3. Then in the validator you can use the table name, column name to apply your validation logic (unique etc).
Thanks,
Paul