I am experiencing some strange behaviour with Hibernate Validator 6.0.9.Final when validating an object. Given the following POJO:
public class Log {
private Long uid;
#javax.validation.constraints.NotEmpty
#javax.validation.constraints.NotNull
private String value;
private long reference;
private String type;
private String createdDt;
private String createdBy;
private Boolean actioned;
private Long dxr;
// Constructors..
// Getters and setters...
// Equals and hashcode overrides...
}
Now, if I validate the entity using a new instance JUnit test I get the following output:
#Test
public void test() {
Log cLog = new Log();
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
Validator beanvalidator = validatorFactory.getValidator();
Set<ConstraintViolation<CommunicationLog>> constraintViolations = beanvalidator.validate(cLog);
System.out.println(constraintViolations);
}
[ConstraintViolationImpl{interpolatedMessage='must not be null', propertyPath=value, rootBeanClass=class Log, messageTemplate='{javax.validation.constraints.NotNull.message}'},
ConstraintViolationImpl{interpolatedMessage='must not be empty', propertyPath=value, rootBeanClass=class Log, messageTemplate='{javax.validation.constraints.NotEmpty.message}'}]
Which is fine. However, if I run this same code on a Hibernate/Jersey project, only the #NotNull validation runs. I cannot seem to get the #NotEmpty validator to run on the object.
I have tried removing the #NotNull validator (as the #NotEmpty validator takes care of it) but I left it on for completeness to demonstrate that the #NotEmpty validator is not returning anything in the image above.
I do not understand why it is not running when deployed to a web project but works fine when running under a JUnit test. Is there something I am missing here?
Okay, so I have resolved this. I hadn't realised that I had deployed the project to the wrong server. I had deployed it to a Payara 4.1.1.171 server instead of a Payara 5.181 server. However, I would have expected some kind of information to have been displayed - perhaps when deploying.
Related
I have ran into a complete stop trying to develop a service using R2dbc. I am building an integration test for it. The service has a huge problem, which while preparing the test data in the integration test I am able to to build, save it in db (h2) and receive the test data from h2 db for entity user.
Sadly when I call the endpoint I am trying to test where data for user has been saved while setting up the test data for user, there in a service class r2dbc fails to instantiate User class while trying to get the object from db. I have defined an empty constructor for User. I am completely stuck at understanding why this instantiation fails. When setting up the test data in the integration test I am able to save and receive rows, but when the integration test reaches the endpoint and the service it just returns the following error while querying:
org.springframework.data.mapping.model.MappingInstantiationException: Failed to instantiate com.x.base.domain.User using constructor com.x.base.domain.User() with arguments
at org.springframework.data.mapping.model.ClassGeneratingEntityInstantiator$EntityInstantiatorAdapter.createInstance(ClassGeneratingEntityInstantiator.java:240)
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Assembly trace from producer [reactor.core.publisher.FluxMapFuseable] :
reactor.core.publisher.Flux.map(Flux.java:6091)
io.r2dbc.h2.H2Result.map(H2Result.java:67)
Error has been observed at the following site(s):
The entity:
#Table("user")
public class User extends AbstractAuditingEntity implements Serializable {
User() {
}
#Id
#Column("id")
#Size(max = 100)
#NotNull
private String id;
#NotNull
#Pattern(regexp = Constants.LOGIN_REGEX)
#Size(min = 1, max = 50)
#Column("login")
private String login;
#Size(max = 50)
#Column("first_name")
private String firstName;
#Size(max = 50)
#Column("last_name")
private String lastName;
....
(getters and builder down below)
}
I have debugged the instantiation to a really low level and have not yet seen anything to cause this error. The DB is found and also the reflections (I do not use setter classes).
The integration test:
// here user is defined and populated - I only use block in the integration tests.
var user = userRepository.create(user).block();
// here I test if the method in the service should work
var userByLogin = userRepository.findOneByLogin(user.getLogin())
TreeDTO treeDTO = webTestClient
.get()
.uri("/api/x/x/" + user.getId())
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus()
.isOk()
.expectHeader()
.contentType(MediaType.APPLICATION_JSON)
.returnResult(TreeDTO.class)
.getResponseBody()
.blockFirst();
Service method, where the instantiation fails:
#Transactional(readOnly = true)
public Mono<DevelopmentTreeDTO> getTreeByUserId(String userId) {
return SecurityUtils.getCurrentUserLogin()
.flatMap(login -> userRepository.findOneByLogin(login) -> error is thrown here (user is authenticated and login is present in securityUtils)
.map(user -> { ...
I tried to keep it as short as possible, but I just am scratching my head with this. Any recommendation is extremely welcome. Thank you in advance!
I have a simple User class and its properties are annotated with both #NotBland and lombok #NonNull.
#AllArgsConstructor
#Data
#Builder
public class User {
#NonNull
private String name;
#NonNull
private String id;
#NotBlank
private String address;
}
What i am expecting from this is when i try to set blank in address field it informs me at compile time or at least crash at runtime. Lombok #NonNull is working in that way and is raising NPEs at runtime.
I wrote the following test to check this
#Test
public void user_null_test(){
User user = User.builder()
.id("")
.name("")
.address("")
.build();
assertThat(user).isNotNull();
But the user is a valid user object with address being empty. Obviously i can use the following code to check for validation in my test
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<User>> violations = validator.validate(user);
assertThat(violations).isEmpty();
but i can't do that or want to write this type of code in my actual code base.
So my question is what is the use of #NotBlank if it does not raise any error at compile or run time if we are setting a property to as empty string when it is not supposed to be so according to the set annotation.
I am using springBoot 2 and I am trying to validate the objects in a List via:
#RequestMapping(value = "/bets",
produces = {"application/json"},
consumes = {"application/json"},
method = RequestMethod.POST
)
void postBets(#RequestBody List<#Valid Bet> bets);
and Bet class has #NotNull annotations on certain attributes.
import javax.validation.constraints.NotNull;
public class Bet extends BetMessage {
#NotNull
private String categoryName;
#NotNull
private String marketName = null;
#NotNull
private OffsetDateTime startTime = null;
#NotNull
private String betName = null;
I have also added the spring-boot-starter-validation artifact to my build file but still no validation is happening.
As a workaround I have implemented the popular answer in the question below (ValidList class) and validation is working as expected; however I think that I am missing something obvious and the solution is now part of the validation library.
Validation of a list of objects in Spring
You may want to write a wrapper which contains your list of Bet because then your wrapper will conform to JavaBean specs and the validations can be applied.
Below Answer might help in this case.
#Valid on list of beans in REST service
We're using MongoDB and Spring Data in our Spring Boot app. Another developer has earlier written a service, using MongoTemplate's findAndModify method, and some additional code that uses that service. It worked fine, even in production.
I've branched and went on adding some new features (completely new code) and needed to call that service. Service doesn't work for me, even though I didn't even touch the service code. Moreover, even the code the other guy wrote before (it's a REST controller calling the service) doesn't work now. On the master branch, everything works like it should.
Here's the service:
#Autowired
private MongoTemplate mongo;
public void addRetention(Date when, String userId, Platform platform) {
LocalDateTime dateTime = LocalDateTime.ofEpochSecond(when.getTime()/1000, 0, ZoneOffset.UTC);
int yyyymm = 100 * dateTime.getYear() + dateTime.getMonthValue();
Retention r = mongo.findAndModify( // the exception is coming from this line
new Query(Criteria.where("userId").is(userId).and("yyyymm").is(yyyymm)),
new Update().inc("count", 1).set("platform", platform),
new FindAndModifyOptions().upsert(true).returnNew(true), Retention.class
);
addRealTimeRetention(userId, r, yyyymm);
}
How I call the service:
retentionService.addRetention(timeService.timeToUtil(usage2.getDate()),
usage2.getUserId(), platform);
And the stack trace on PasteBin. The exception message is:
IllegalArgumentException: Target bean is not of type of the persistent entity!
EDIT: Here's the Retention.java class:
#Document
#JsonInclude(JsonInclude.Include.NON_NULL)
#CompoundIndexes({
#CompoundIndex(name = "userid_yyyymm_idx", def = "{ userId: 1, yyyymm: 1 }")
})
public class Retention {
#Id
private String id;
#Indexed
private String userId;
#Indexed
private int yyyymm;
private int count;
private Platform platform;
// setters and getters...
}
FINAL EDIT: I solved this by deleting spring devtools dependency in pom.xml. I'm not sure how that dependency has anything to do with this exception. Found the solution here. Thank you to everyone who helped out.
I'm experimenting with JPA and Glassfish 4.0.
I've written a user class like this (just relevant parts and i'm not sure if it compiles):
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 50)
#Column(name = "first_name")
private String firstName;
#JoinColumn(name = "country_id", referencedColumnName = "id")
#ManyToOne(optional = false)
private Country country;
public void setCountry(Country countryId) {
this.country = countryId;
}
}
My TestController (just relevant parts):
#ManagedBean(name = "testController", eager = true)
#RequestScoped
public class TestController implements Serializable {
#EJB
private dk.iqtools.session.UserFacade userFacade;
public String Insert(){
factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
EntityManager em = factory.createEntityManager();
Query cq = em.createQuery("select c from Country c where c.id = 302");
List<Country> countryList = cq.getResultList();
User user = new User();
user.setFirstName("Hans123");
user.setLastName("Knudsen333");
user.setCountry((Country)countryList.get(0)); <- throws an ERROR
user.setPassword("secret");
user.setYearOfBirth(1966);
user.setGender(1);
user.setEmail("haps#hfhfh.dk2243");
userFacade.create(user);
return "";
}
And my Country bean is just a plain bean with simple attibutes located in:
dk.iqtools.entity
In general it works, but if i encounter an error in my code i persistently receive the following error:
Caused by: java.lang.ClassCastException:
dk.iqtools.entity.Country cannot be cast to dk.iqtools.entity.Country
at dk.iqtools.controller.TestController.Insert(TestController.java:65)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
the offending statement is this:
user.setCountry((Country)countryList.get(0));
Can anybody tell my why it happens? If everything runs as expected the user is inserted into the database. But if i for instanse tries to insert a user that already exists i receive a database error.
Next time through i receive the weird exception. I can't understand why a class can't be cast to itself.
I have to restart my GF instance to get rid of it.
Not very production-like.
Thanks for any input.
It happens because of some left overs from the EntityManagerFactory from the old version of your application, somehow its classloaders survived after you redeployed you app.
What you need to do is to close the EntityManagerFactory just before the redeployment occur, you can use ServletContextListeners to achieve that, they allow you to attach events to your web app initialization and destruction.
Here is a very simple example of a ServletContextListener implementation: http://4dev.tech/2015/08/example-of-servletcontextlistener-implementation/
I have just had to deal with this same type of Exception; "Can't cast X to X." Where "X" is the same class.
It turned out to be 2 problems feeding into each other. I had made a change in some of my code's pom.xml file (maven's makefile) that said my class was "to be included" (compiled instead of provided) in the WAR file. But it was also available in the "outer" EAR module.
The class loader was dealing with 2 different instances of the same jar file (i.e., 2 copies of it). This made the class loader think it was 2 different classes, causing the Exception.
To ultimately fix it I had to change compiled to provided in the WAR file pom.xml, but make sure the EAR file's pom did include the projects jar files.
But then I also had to take the step to make sure that I had run "clean" to delete all the WAR and EAR file's jar library contents so that there were no extra copies to be found.
It can get confusing to sort out the contents of the files since the WAR was in the EAR and you had to un-zip the WAR to get a listing of its contents and running the build multiple times made for differing dates on the files.