i have updated an old spring boot 1.5.3 project to spring boot 2.0.0. RELEASE.
I have an auditing entity with two fields of type ZonedDateTime annotated with #CreatedBy and #LastModifiedDate.
In the previous versions everything was working fine. However, with the new update, upon saving the entity in the repository i get an error i.e
createdDate=<null>
lastModifiedDate=<null>
]! Supported types are [org.joda.time.DateTime, org.joda.time.LocalDateTime, java.util.Date, java.lang.Long, long]
I checked the AnnotationAuditingMetaData, and i found noting related to ZonedDateTime.
There is also this issue in https://jira.spring.io/browse/DATAJPA-1242, I believe it's related.
My question is what am i doing wrong here, does spring stopped the support or am i doing something wrong?
I had the same problem and could solve it adding a dateTimeProviderRef to #EnableJpaAuditing.
Java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.auditing.DateTimeProvider;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import java.time.ZonedDateTime;
import java.util.Optional;
#Configuration
#EnableJpaAuditing(dateTimeProviderRef = "auditingDateTimeProvider")
public class PersistenceConfig {
#Bean // Makes ZonedDateTime compatible with auditing fields
public DateTimeProvider auditingDateTimeProvider() {
return () -> Optional.of(ZonedDateTime.now());
}
}
Kotlin
#Configuration
#EnableJpaAuditing(dateTimeProviderRef = "auditingDateTimeProvider")
class PersistenceConfig {
#Bean // Makes ZonedDateTime compatible with auditing fields
fun auditingDateTimeProvider()= DateTimeProvider { of(ZonedDateTime.now()) }
}
Old answer was mistaken, but I can't delete it because it is accepted. Please scroll to other answers.
You also have to put this annotation
#EntityListeners(AuditingEntityListener.class)
on the class where you use the #CreatedDate.
Related
I've been searching for the simplest and best way to validate my entities before they are created/updated and after much googling, I couldn't find a clean/modern one.
Ideally, I would have loved to be able to use #Valid as follows:
import javax.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.rest.core.annotation.HandleBeforeCreate;
import org.springframework.data.rest.core.annotation.HandleBeforeSave;
import org.springframework.data.rest.core.annotation.RepositoryEventHandler;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
#Slf4j
#Validated
#Component
#RepositoryEventHandler
public class CustomerEventHandler {
// Triggered for POST
#HandleBeforeCreate
public void onBeforeCreate(#Valid Customer entity) {
log.info("Saving new entity {}", entity);
}
// Triggered for PUT / PATCH
#HandleBeforeSave
public void onBeforeSave(#Valid Customer entity) {
log.info("Saving new entity {}", entity);
}
}
The Customer entity being:
import javax.validation.constraints.NotBlank;
#Getter
#Setter
#ToString
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "customer")
public class Customer {
#NotBlank
private String firstname;
}
But it doesn't seem to work.
What's the modern, easy way to validate entities in Spring Data REST?
Note: I'm using Spring Boot
I checked your pom.xml in linked GitHub project. You have just a dependency to validation annotations, but the proper way with Spring Boot is to use the spring-boot-starter-validation Dependency. The Spring Boot Starter Dependencies add the "magic" to your project, which triggers automatically the validation based on your annotations.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
I my German blog I have written an article about this topic:
https://agile-coding.blogspot.com/2020/11/validation-with-spring.html
I want to suggest a few best practise that every developer, who starting as junior/beginner should be know. Don't put any Validation annotation in Entities, using them in DTO/Resource classes. and the best way to practise validation is that you can handler MethodArgumentNotValidation exception in your own Spring Boot of Exception Handler class annotated that class #RestControllerAdvice and create your own #interface annotation instead of using more validation annotation.
I have a Pojo (annotated with Lombok if it makes any difference) and a RestController in a Spring Boot app. The pojo method parameter is annotated with #Valid yet there is no validation applied and even if I add a BindingResult second parameter, it never has any error. I'm testing this with Swagger UI, posting a JSON, but I don't see why that would make any differnce... Did I miss something obvious?
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Tolerate;
import org.springframework.data.mongodb.core.mapping.Document;
import javax.validation.constraints.NotBlank;
#Data
#EqualsAndHashCode(callSuper = true)
#Builder
public class MyPojo extends GenericDocument {
#NotBlank
private String name;
#Tolerate
public MyPojo() {
}
}
import javax.validation.Valid;
#RestController
#RequestMapping(value = "/myUrl", produces = APPLICATION_JSON_VALUE)
public class MyController {
#PostMapping
public ResponseEntity<MyPojo> createNew(#RequestBody #Valid MyPojo pojo){...
}
}
Solution
Adding this dependency was enough:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
It is strange that adding javax.validation:validation-api and org.hibernate:hibernate-validator was not enough despite the documentation
You should try adding Spring’s #Validated annotation to the controller at class level to tell Spring to evaluate the constraint annotations on method parameters.
Example:
#Slf4j
#Validated
#RestController
#RequestMapping(value = "/myUrl", produces = APPLICATION_JSON_VALUE)
public class MyController {
#PostMapping
public ResponseEntity<MyPojo> createNew(#RequestBody #Valid MyPojo pojo){...
}
}
This org.springframework.validation.annotation.Validated annotation can be applied at both class level and method or parameter level.
Per the documentation, which is not entirely clear, you need to have a JSR-303 validation provider such as Hibernate Validator (docs here) on your classpath so Spring can detect and use it.
It also seems in some cases you may need the Spring Boot Starter Validation dependency (spring-boot-starter-validation) on your classpath as well. I would suggest trying that to see if it helps. (Strangely, though, I don't see that detailed in the Spring docs - just briefly mentioned here.)
Or you could maybe implement the Validator interface as per here, but not sure.
I am trying to use Spring data and repositories in a Spring Boot application, but I have an error when compiling the project.
Here is my Entity :
package fr.investstore.model;
import javax.persistence.Id;
...
#Entity
public class CrowdOperation {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
public Long id;
#Enumerated(EnumType.STRING)
public RepaymentType repaymentType;
...
}
And the corresponding Repository:
package fr.investstore.repositories;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import fr.investstore.model.CrowdOperation;
public interface CrowdOperationRepository extends CrudRepository<CrowdOperation, Long> {
}
I use it in a WS controller, generating a repository through the Autowired annotation:
package fr.investstore.ws;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMapping;
...
#Controller
#EnableAutoConfiguration
public class SampleController {
#Autowired
private CrowdOperationRepository crowdOperationRepository;
#RequestMapping(path = "/", method = RequestMethod.GET)
#ResponseBody
public String getOperations(#RequestParam(required=true, defaultValue="Stranger") String name) {
crowdOperationRepository.save(new CrowdOperation());
return "Hello " + name;
}
}
And the code of the application:
package fr.investstore;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import fr.investstore.ws.SampleController;
#SpringBootApplication
public class InvestStoreApplication {
public static void main(String[] args) {
SpringApplication.run(SampleController.class, args);
}
}
But when compiling the project I get:
APPLICATION FAILED TO START
Description: Field crowdOperationRepository in
fr.investstore.ws.SampleController required a bean of type
'fr.investstore.repositories.CrowdOperationRepository' that could not
be found.
Action: Consider defining a bean of type
'fr.investstore.repositories.CrowdOperationRepository' in your
configuration.
Woudn't Spring automatically generate a bean for the repository through the interface?
How can I resolve this?
EDIT: I also tried to put the Repository annotation (from org.springframework.stereotype.Repository) onto CrowdOperationRepository, but I got the same error
While creating a spring-boot application, we need to keep some point in our mind like
Always keep main class (class with `#SpringBootApplication annotation) on the top level package and other classes should lie under sub-packages.
Always mark your bean classes with proper annotation e.g. all repositories should be marked by #Repository annotation, all service implementation classes should be marked with #Service, other component classes should be marked by #Component, class which defines our beans should be marked as #Configuration
Enable the feature which you are using e.g. #EnableJpaRepositories, #EnableTransactionManagement, #EnableJpaAuditing, these annotations also provides functionality which let us define which package spring needs to scan.
So in your case, you need to mark InvestStoreApplication class with #EnableJpaRepositories annotation and CrowdOperationRepository with #Repository.
you have to tell your spring boot application to load JPA repositories.
copy this one to your application class
it will auto-scan your JPA repository and load it in your spring container even if you do not define your interface with #Repository it will wire that bean in your dependent class.
#EnableJpaRepositories(basePackages = { "fr.investstore.repositories" })
Thank to #JBNizet for his comment, that made it working.
I create this answer since he did not:
Replace SpringApplication.run(SampleController.class, args); with SpringApplication.run(InvestStoreApplication.class, args);. And remove the useless #EnableAutoConfiguration on your controller.
Annotating your entity class as shown as spring hint below to allow spring get a valid repository bean
Spring Data JPA - Could not safely identify store assignment for repository candidate interface com.xxxxx.xxxxRepository.
If you want this repository to be a JPA repository, consider annotating your entities with one of these annotations: javax.persistence.Entity, javax.persistence.MappedSuperclass (preferred),
or consider extending one of the following types with your repository: org.springframework.data.jpa.repository.JpaRepository.
2022-05-06 12:32:12.623 [ restartedMain] INFO [.RepositoryConfigurationDelegate:201 ] - Finished Spring Data repository scanning in 3 ms. Found 0 JPA repository interfaces.
I am developing an application managed by amazon simple workflow and spring 4 with annotation based dependency injection.
IMyActivity.java
package com.test.activities;
import com.amazonaws.services.simpleworkflow.flow.annotations.Activities;
import com.amazonaws.services.simpleworkflow.flow.annotations.ActivityRegistrationOptions;
#ActivityRegistrationOptions(defaultTaskScheduleToStartTimeoutSeconds = 3000,
defaultTaskStartToCloseTimeoutSeconds = 100)
#Activities(version="1.0")
public interface IMyActivity {
String dofunc();
}
MyActivityImpl.java
package com.test.activities;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.test.services.TransactionService;
#Component
public class MyActivityImpl implements IMyActivity {
#Autowired
private ITransactionService transactionService;
#Override
public String dofunc() {
return transactionService.dosomething();
}
}
The problem I am facing is that when the activity is scheduled by swf,ITransactionService implementation is not getting injected and transactionServiceis null. However, everything works fine when the IMyActivity myactivity is #Autowired from anywhere else and is not called by swf.
Am I doing something wrong here? Please help.
Check if your MyActivityImpl class located in package that specified in component scan settings. If you use java config:
#ComponentScan(basePackages = "")
and if you use xml config:
<context:component-scan base-package=""/>
I followed this documentation http://docs.aws.amazon.com/amazonswf/latest/awsflowguide/test.html#test.spring. This is the official amazon swf documentation for its integration using spring. Worked like a charm.
I would like to know the difference between JPA and Hibernate. I have read the very interesting question posted by #Anthony with interest but still I do not understand the full picture.
I have implemented my application in Spring MVC and Hibernate (see below). My DAOs are an implementation of services which have been built using HQL queries.
#Service("messagesService")
public class MessagesService
{
private MessagesDAO messagesDAO;
#Autowired
public void setMessagesDAO(MessagesDAO messagesDAO)
{
this.messagesDAO = messagesDAO;
}
public List<Message> getAllMessages()
{
return messagesDAO.getAllMessages();
}
...
--------
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
#Repository
#Transactional
#Component("messagesDAO")
public class MessagesDAO
{
#Autowired
private SessionFactory sessionFactory;
public Session session()
{
return sessionFactory.getCurrentSession();
}
#SuppressWarnings("unchecked")
public List<Message> getAllMessages()
{
Criteria crit = session().createCriteria(Message.class);
crit.createAlias("usernameSender", "u").add(Restrictions.eq("u.enabled",true));
return crit.list();
}
...
I really like the statement "JPA is the dance, Hibernate is the dancer." but in my specific case I do not fully get why my example is not JPA. MessageService is the dance and MessagesDAO the dancer(Implementation).
As #Kevin states:
Think of JPA as the guidelines that must be followed or an interface,
while Hibernate's JPA implementation is code that meets the API as
defined by the JPA specification and provides the under the hood
functionality.
I know I have not defined my service as an interface but this still lets me think that my code complies with the JPA specification requirements.
Now a concern arises
What is the difference between my example and the following from the pet clinic example
package org.springframework.samples.petclinic.repository;
import java.util.List;
import org.springframework.dao.DataAccessException;
import org.springframework.samples.petclinic.model.BaseEntity;
import org.springframework.samples.petclinic.model.Pet;
import org.springframework.samples.petclinic.model.PetType;
public interface PetRepository {
List<PetType> findPetTypes() throws DataAccessException;
-------
#Repository
public class JpaPetRepositoryImpl implements PetRepository {
#PersistenceContext
private EntityManager em;
#Override
#SuppressWarnings("unchecked")
public List<PetType> findPetTypes() {
return this.em.createQuery("SELECT ptype FROM PetType ptype ORDER BY ptype.name").getResultList();
}
The reason why I am asking all this questions is because I am using MySql in my application and I am thinking to change it in the future.
Therefore, I am trying to build my implementation layer to avoid any problem later on.
I was looking at nosql options and I discovered spring data jpa for the integration layer. I then started to learn a bit more about JPA and DAOs and the questions above suddenly arose
If I implement spring data jpa, can I use MySql for the moment and change it later to another database (Cassandra, MongoDb)?
What is the difference between Spring data JPA and Spring Data Mongodb
(The first is the specification and the second one the implementation?)
Thank you for your help
To keep the terminology: In your DAO you can't change your dancing partner.
Why? Because you are referencing Hibernate explicitly. If you would like to change the dancer some day you would have to change your whole implementation. Thats why you usually use only classes of the dance - JPA or Spring Data in your case.