I've been at this for a while, but I have a Spring managed custom validator that looks like the below, I have some print statements in there which I'll get to later
#Component
public class BulkUpdateValidator implements ConstraintValidator<ValidBulkUpdate, BulkUpdate> {
#Autowired
ObjectMapper mapper;
public BulkUpdateValidator(){
System.out.println(this.toString());
}
#PostConstruct
public void post(){
System.out.println(mapper);
System.out.println(this.toString());
}
public boolean isValid(BulkUpdate update, ConstraintValidatorContext context){
System.out.println(this.toString());
System.out.println(mapper);
}
... other validator methods ...
}
My controller method: (NOTE: my controller class is annotated with #Validated at the top)
#RequestMapping(...)
public #ResponseBody RestResponse bulkUpdate(#Valid #ValidBulkUpdate Bulkupdate bulkUpdate){
... stuff here ...
}
My Bean:
public class BulkUpdate {
#NotEmpty
public List<String> recordIds;
#NotEmpty
#Valid
public List<FieldUpdate> updates;
.... getters and setters ....
}
Here's my problem, when I execute the endpoint it get a NullPointerException when I attempt to use the autowired mapper. The output from the print statements I posted above are quite telling. In both the constructor and the #PostConstruct sections I get the same Object ID for the validator and I also get an ID for the mapper. However, once isValid is called, it prints out a different Object ID. I know the spring managed validator is being created, but it's not being used.
Furthermore, I've tried to remove the #ValidBulkUpdate annotation from the REST endpoint and put it inside a wrapper object, thinking that maybe #Valid was necessary to get spring to take over, like below:
public #ResponseBody RestResponse bulkUpdate(#Valid BulkupdateWrapper bulkUpdate){
... stuff here ...
}
And wrapper
public class BulkUpdateWrapper {
#ValidBulkUpdate
private BulkUpdate update;
.... getter and setter ....
}
This leaves me with a whole new error which is even weirder:
"JSR-303 validated property 'update.org.hibernate.validator.internal.engine.ConstraintViolationImpl' does not have a corresponding accessor"
I'm not sure where to turn, hopefully someone has an idea. Either how to get it to use the Spring managed validator, or how to remove that vague error when I use the object wrapper;
What's worse, is I have MockMvc based Integration tests for this that run flawlessly, this only happens when I deploy it.
UPDATE
So I kept my wrapper and changed #Valid to #Validated and now my error is the following: "NotReadablePropertyException: Bean property 'update.field' does not have a corresponding accessor for Spring data binding"
Fun fact, there is no property called "field"
Related
Spring cache is not working when calling cached method from another method of the same bean.
Here is an example to explain my problem in clear way.
Configuration:
<cache:annotation-driven cache-manager="myCacheManager" />
<bean id="myCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="myCache" />
</bean>
<!-- Ehcache library setup -->
<bean id="myCache"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:shared="true">
<property name="configLocation" value="classpath:ehcache.xml"></property>
</bean>
<cache name="employeeData" maxElementsInMemory="100"/>
Cached service :
#Named("aService")
public class AService {
#Cacheable("employeeData")
public List<EmployeeData> getEmployeeData(Date date){
..println("Cache is not being used");
...
}
public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){
List<EmployeeData> employeeData = getEmployeeData(date);
...
}
}
Result :
aService.getEmployeeData(someDate);
output: Cache is not being used
aService.getEmployeeData(someDate);
output:
aService.getEmployeeEnrichedData(someDate);
output: Cache is not being used
The getEmployeeData method call uses cache employeeData in the second call as expected. But when the getEmployeeData method is called within the AService class (in getEmployeeEnrichedData), Cache is not being used.
Is this how spring cache works or am i missing something ?
I believe this is how it works. From what I remember reading, there is a proxy class generated that intercepts all requests and responds with the cached value, but 'internal' calls within the same class will not get the cached value.
From https://code.google.com/p/ehcache-spring-annotations/wiki/UsingCacheable
Only external method calls coming in through the proxy are
intercepted. This means that self-invocation, in effect, a method
within the target object calling another method of the target object,
will not lead to an actual cache interception at runtime even if the
invoked method is marked with #Cacheable.
Since Spring 4.3 the problem could be solved using self-autowiring over #Resource annotation:
#Component
#CacheConfig(cacheNames = "SphereClientFactoryCache")
public class CacheableSphereClientFactoryImpl implements SphereClientFactory {
/**
* 1. Self-autowired reference to proxified bean of this class.
*/
#Resource
private SphereClientFactory self;
#Override
#Cacheable(sync = true)
public SphereClient createSphereClient(#Nonnull TenantConfig tenantConfig) {
// 2. call cached method using self-bean
return self.createSphereClient(tenantConfig.getSphereClientConfig());
}
#Override
#Cacheable(sync = true)
public SphereClient createSphereClient(#Nonnull SphereClientConfig clientConfig) {
return CtpClientConfigurationUtils.createSphereClient(clientConfig);
}
}
The example below is what I use to hit the proxy from within the same bean, it is similar to #mario-eis' solution, but I find it a bit more readable (maybe it's not:-). Anyway, I like to keep the #Cacheable annotations at the service level:
#Service
#Transactional(readOnly=true)
public class SettingServiceImpl implements SettingService {
#Inject
private SettingRepository settingRepository;
#Inject
private ApplicationContext applicationContext;
#Override
#Cacheable("settingsCache")
public String findValue(String name) {
Setting setting = settingRepository.findOne(name);
if(setting == null){
return null;
}
return setting.getValue();
}
#Override
public Boolean findBoolean(String name) {
String value = getSpringProxy().findValue(name);
if (value == null) {
return null;
}
return Boolean.valueOf(value);
}
/**
* Use proxy to hit cache
*/
private SettingService getSpringProxy() {
return applicationContext.getBean(SettingService.class);
}
...
See also Starting new transaction in Spring bean
Here is what I do for small projects with only marginal usage of method calls within the same class. In-code documentation is strongly advidsed, as it may look strage to colleagues. But its easy to test, simple, quick to achieve and spares me the full blown AspectJ instrumentation. However, for more heavy usage I'd advice the AspectJ solution.
#Service
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class AService {
private final AService _aService;
#Autowired
public AService(AService aService) {
_aService = aService;
}
#Cacheable("employeeData")
public List<EmployeeData> getEmployeeData(Date date){
..println("Cache is not being used");
...
}
public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){
List<EmployeeData> employeeData = _aService.getEmployeeData(date);
...
}
}
If you call a cached method from same bean it will be treated as a private method and annotations will be ignored
Yes, the caching will not happen because of the reasons that were already mentioned in the other posts. However I would solve the problem by putting that method to its own class (service in this case). With that your code will be easier to maintain/test and understand.
#Service // or #Named("aService")
public class AService {
#Autowired //or how you inject your dependencies
private EmployeeService employeeService;
public List<EmployeeData> getEmployeeData(Date date){
employeeService.getEmployeeData(date);
}
public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){
List<EmployeeData> employeeData = getEmployeeData(date);
...
}
}
#Service // or #Named("employeeService")
public class EmployeeService {
#Cacheable("employeeData")
public List<EmployeeData> getEmployeeData(Date date){
println("This will be called only once for same date");
...
}
}
In my Case I add variable :
#Autowired
private AService aService;
So I call the getEmployeeData method by using the aService
#Named("aService")
public class AService {
#Cacheable("employeeData")
public List<EmployeeData> getEmployeeData(Date date){
..println("Cache is not being used");
...
}
public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){
List<EmployeeData> employeeData = aService.getEmployeeData(date);
...
}
}
It will use the cache in this case.
Better approach should be creating another service like ACachingService and call ACachingService.cachingMethod() instead of self Autowiring ( or any other approach trying to self inject). This way you do not fall into Circular dependency, which may be resulted in warning/error when upgrade to newer Spring ( Spring 2.6.6 in my case ) :
ERROR o.s.boot.SpringApplication - Application run failed
org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'webSecurityConfig':
Requested bean is currently in creation: Is there an unresolvable circular reference?
We looked at all the solutions here and decided to use a separate class for the cached methods because Spring 5 doesn't like circular dependencies.
Use static weaving to create proxy around your bean. In this case even 'internal' methods would work correctly
I use internal inner bean (FactoryInternalCache) with real cache for this purpose:
#Component
public class CacheableClientFactoryImpl implements ClientFactory {
private final FactoryInternalCache factoryInternalCache;
#Autowired
public CacheableClientFactoryImpl(#Nonnull FactoryInternalCache factoryInternalCache) {
this.factoryInternalCache = factoryInternalCache;
}
/**
* Returns cached client instance from cache.
*/
#Override
public Client createClient(#Nonnull AggregatedConfig aggregateConfig) {
return factoryInternalCache.createClient(aggregateConfig.getClientConfig());
}
/**
* Returns cached client instance from cache.
*/
#Override
public Client createClient(#Nonnull ClientConfig clientConfig) {
return factoryInternalCache.createClient(clientConfig);
}
/**
* Spring caching feature works over AOP proxies, thus internal calls to cached methods don't work. That's why
* this internal bean is created: it "proxifies" overloaded {#code #createClient(...)} methods
* to real AOP proxified cacheable bean method {#link #createClient}.
*
* #see Spring Cache #Cacheable - not working while calling from another method of the same bean
* #see Spring cache #Cacheable method ignored when called from within the same class
*/
#EnableCaching
#CacheConfig(cacheNames = "ClientFactoryCache")
static class FactoryInternalCache {
#Cacheable(sync = true)
public Client createClient(#Nonnull ClientConfig clientConfig) {
return ClientCreationUtils.createClient(clientConfig);
}
}
}
I would like to share what I think is the easiest approach:
Autowire the controller and use to call the method it instead of using the class context this.
The updated code would look like:
#Controller
public class TestController {
#Autowired TestController self;
#RequestMapping("/test")
public String testView(){
self.expensiveMethod();
return "test";
}
#Cacheable("ones")
public void expensiveMethod(){
System.out.println("Cache is not being used");
}
}
The default advice mode for processing caching annotation is “proxy”. At the startup of an application, all the caching annotations like #Caching, #Cacheable, #CacheEvict etc. are scanned and a target proxy class is generated for all of these classes. The proxy allows for intercepting the calls to these cacheable methods, which adds the caching advice/behavior.
So when we invoke the cacheable methods from the same class, as shown below, calls from the clients don’t get intercepted in a way that allows for caching advice to be added to them. Hence, every single time there is an unexpected cache miss.
Solution: Invoke the Cacheable methods from a different bean to use proxy class with caching advice.
I'm using #Value to inject parameters from my properties file to variable in my application.
Because I'm not the only user in the application and I want to make the injection safety I need to validate the parameter before the injection.
Example:
properties file:
example.string=str1,str2
app.java
#Value(${example.string})
public String example;
the expected behavior in this case for example is to throw an exception because I assume "," id delimiter in array case
I don't think you can directly with #Value. But you could do something like this, which will fail on startup if validation fails:
#Validated
#ConfigurationProperties(prefix="my.prefix")
public class AppProperties {
//Validation annotations here
//#NotEmpty
//#MyCustomValidation
private String exampleString;
// getters / setters
}
I don't think you can do this before the injection, try to use the post construct method
you can do some thing like that :
#PostConstruct
public void validateValue() {
if (someProperty.contains(",")) {
throw new MyException("error");
}
}
I have a custom annotation #UniqueModel, which is validated by a ConstraintValidator:
#Component
public class UniquePlaceValidator implements ConstraintValidator<UniqueModel, Model> {
#Autowired
private ModelRepository repository;
public UniqueModelValidator() {
}
public void initialize(UniqueModel constraint) {
}
#Override
public boolean isValid(Model model, ConstraintValidatorContext context) {
if (repository == null)
return true;
Model dbModel = repository.findByNameAndMail(model.getName(), model.getMail());
return dbModel == null;
}
The problem is, that I need to do the validation before the safe()-method of the repository is called, otherwise the field injection won't work.
I therefor created a delegate-method with a #Valid-annotation, in order to force the unique-validation before:
Model save(#Valid Model model {
return repository.save(model);
}
Unfortunately this doesn't work, it seems like the #Valid-annotation is ignored by Spring.
How can I assure the correct timing of validation?
Depending on your Bean validation configuration you may need to annotate your repository bean with #ValidateOnExecution.
But I'm not sure if Spring does support this annoation (see SPR-10641) hence I'm using Spring's own #Validated annotation in my repository and service interfaces and method level validation works fine!
See also this question and have a look into MethodValidationPostProcessor which clearly states "Target classes with such annotated methods need to be annotated with Spring's #Validated annotation at the type level". So it seems to be pretty clear that you have to use #Validated instead of #ValidateOnExecution until SPR-10641 is fixed.
Hej,
I want to use the #Validated(group=Foo.class) annotation to validate an argument before executing a method like following:
public void doFoo(Foo #Validated(groups=Foo.class) foo){}
When i put this method in the Controller of my Spring application, the #Validated is executed and throws an error when the Foo object is not valid. However if I put the same thing in a method in the Service layer of my application, the validation is not executed and the method just runs even when the Foo object isn't valid.
Can't you use the #Validated annotation in the service layer ? Or do I have to do configure something extra to make it work ?
Update:
I have added the following two beans to my service.xml:
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>
and replaced the #Validate with #Null like so:
public void doFoo(Foo #Null(groups=Foo.class) foo){}
I know it is a pretty silly annotation to do but I wanted to check that if I call the method now and passing null it would throw an violation exception which it does. So why does it execute the #Null annotation and not the #Validate annotation ? I know one is from javax.validation and the other is from Spring but I do not think that has anything to do with it ?
In the eyes of a Spring MVC stack, there is no such thing as a service layer. The reason it works for #Controller class handler methods is that Spring uses a special HandlerMethodArgumentResolver called ModelAttributeMethodProcessor which performs validation before resolving the argument to use in your handler method.
The service layer, as we call it, is just a plain bean with no additional behavior added to it from the MVC (DispatcherServlet) stack. As such you cannot expect any validation from Spring. You need to roll your own, probably with AOP.
With MethodValidationPostProcessor, take a look at the javadoc
Applicable methods have JSR-303 constraint annotations on their
parameters and/or on their return value (in the latter case specified
at the method level, typically as inline annotation).
Validation groups can be specified through Spring's Validated
annotation at the type level of the containing target class, applying
to all public service methods of that class. By default, JSR-303 will
validate against its default group only.
The #Validated annotation is only used to specify a validation group, it doesn't itself force any validation. You need to use one of the javax.validation annotations like #Null or #Valid. Remember that you can use as many annotations as you would like on a method parameter.
As a side note on Spring Validation for methods:
Since Spring uses interceptors in its approach, the validation itself is only performed when you're talking to a Bean's method:
When talking to an instance of this bean through the Spring or JSR-303 Validator interfaces, you'll be talking to the default Validator of the underlying ValidatorFactory. This is very convenient in that you don't have to perform yet another call on the factory, assuming that you will almost always use the default Validator anyway.
This is important because if you're trying to implement a validation in such a way for method calls within the class, it won't work. E.g.:
#Autowired
WannaValidate service;
//...
service.callMeOutside(new Form);
#Service
public class WannaValidate {
/* Spring Validation will work fine when executed from outside, as above */
#Validated
public void callMeOutside(#Valid Form form) {
AnotherForm anotherForm = new AnotherForm(form);
callMeInside(anotherForm);
}
/* Spring Validation won't work for AnotherForm if executed from inner method */
#Validated
public void callMeInside(#Valid AnotherForm form) {
// stuff
}
}
Hope someone finds this helpful. Tested with Spring 4.3, so things might be different for other versions.
#pgiecek You don't need to create a new Annotation. You can use:
#Validated
public class MyClass {
#Validated({Group1.class})
public myMethod1(#Valid Foo foo) { ... }
#Validated({Group2.class})
public myMethod2(#Valid Foo foo) { ... }
...
}
Be careful with rubensa's approach.
This only works when you declare #Valid as the only annotation. When you combine it with other annotations like #NotNull everything except the #Valid will be ignored.
The following will not work and the #NotNull will be ignored:
#Validated
public class MyClass {
#Validated(Group1.class)
public void myMethod1(#NotNull #Valid Foo foo) { ... }
#Validated(Group2.class)
public void myMethod2(#NotNull #Valid Foo foo) { ... }
}
In combination with other annotations you need to declare the javax.validation.groups.Default Group as well, like this:
#Validated
public class MyClass {
#Validated({ Default.class, Group1.class })
public void myMethod1(#NotNull #Valid Foo foo) { ... }
#Validated({ Default.class, Group2.class })
public void myMethod2(#NotNull #Valid Foo foo) { ... }
}
As stated above to specify validation groups is possible only through #Validated annotation at class level. However, it is not very convenient since sometimes you have a class containing several methods with the same entity as a parameter but each of which requiring different subset of properties to validate. It was also my case and below you can find several steps to take to solve it.
1) Implement custom annotation that enables to specify validation groups at method level in addition to groups specified through #Validated at class level.
#Target({ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface ValidatedGroups {
Class<?>[] value() default {};
}
2) Extend MethodValidationInterceptor and override determineValidationGroups method as follows.
#Override
protected Class<?>[] determineValidationGroups(MethodInvocation invocation) {
final Class<?>[] classLevelGroups = super.determineValidationGroups(invocation);
final ValidatedGroups validatedGroups = AnnotationUtils.findAnnotation(
invocation.getMethod(), ValidatedGroups.class);
final Class<?>[] methodLevelGroups = validatedGroups != null ? validatedGroups.value() : new Class<?>[0];
if (methodLevelGroups.length == 0) {
return classLevelGroups;
}
final int newLength = classLevelGroups.length + methodLevelGroups.length;
final Class<?>[] mergedGroups = Arrays.copyOf(classLevelGroups, newLength);
System.arraycopy(methodLevelGroups, 0, mergedGroups, classLevelGroups.length, methodLevelGroups.length);
return mergedGroups;
}
3) Implement your own MethodValidationPostProcessor (just copy the Spring one) and in the method afterPropertiesSet use validation interceptor implemented in step 2.
#Override
public void afterPropertiesSet() throws Exception {
Pointcut pointcut = new AnnotationMatchingPointcut(Validated.class, true);
Advice advice = (this.validator != null ? new ValidatedGroupsAwareMethodValidationInterceptor(this.validator) :
new ValidatedGroupsAwareMethodValidationInterceptor());
this.advisor = new DefaultPointcutAdvisor(pointcut, advice);
}
4) Register your validation post processor instead of Spring one.
<bean class="my.package.ValidatedGroupsAwareMethodValidationPostProcessor"/>
That's it. Now you can use it as follows.
#Validated(groups = Group1.class)
public class MyClass {
#ValidatedGroups(Group2.class)
public myMethod1(Foo foo) { ... }
public myMethod2(Foo foo) { ... }
...
}
I want to reinject singleton-scoped dependencies into prototype Spring beans, after they have been deserialized.
Say I've got a Process bean, which depends on a Repository bean. The Repository bean is a scoped as a singleton, but the Process bean is prototype-scoped. Periodically I serialize the Process, and then later deserialize it.
class Process {
private Repository repository;
// getters, setters, etc.
}
I don't want to serialize and deserialize the Repository. Nor do I want to put "transient" on the member variable that holds a reference to it in Process, nor a reference to some kind of proxy, or anything other than a plain old member variable declared as a Repository.
What I think I want is for the Process to have its dependency filled with a serializable proxy that points (with a transient reference) to the Repository, and, upon deserialization, can find the Repository again. How could I customize Spring to do that?
I figure I could use a proxy to hold the dependency references, much like . I wish I could use that exact technique. But the proxy I've seen Spring generate isn't serializable, and the docs say that if I use it with a singleton bean, I'll get an exception.
I could use a custom scope, perhaps, on the singleton beans, that would always supply a proxy when asked for a custom-scoped bean. Is that a good idea? Other ideas?
I used this instead, without any proxy:
public class Process implements HttpSessionActivationListener {
...
#Override
public void sessionDidActivate(HttpSessionEvent e) {
ServletContext sc = e.getSession().getServletContext();
WebApplicationContext newContext = WebApplicationContextUtils
.getRequiredWebApplicationContext(sc);
newContext.getAutowireCapableBeanFactory().configureBean(this, beanName);
}
}
The example is for a web environment when the application server serializes the session, but it should work for any ApplicationContext.
Spring provides a solution for this problem.
Take a look at the spring documentation http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-atconfigurable.
7.8.1 Using AspectJ to dependency inject domain objects with Spring
...
The support is intended to be used for objects created outside
of the control of any container. Domain objects often fall into
this category because they are often created programmatically
using the new operator, or by an ORM tool as a result of a database query.
The trick is to use load time weaving. Just start the jvm with -javaagent:path/to/org.springframework.instrument-{version}.jar. This agent will recognize every object that is instantiated and if it is annotated with #Configurable it will configure (inject #Autowired or #Resource dependencies) that object.
Just change the Process class to
#Configurable
class Process {
#Autowired
private transient Repository repository;
// getters, setters, etc.
}
Whenever you create a new instance
Process process = new Process();
spring will automatically inject the dependencies.
This also works if the Process object is deserialized.
How about added using aspects to add an injection step when you deserialize the object?
You would need AspectJ or similar for this. It would work very similarly to the #Configurable function in Spring.
e.g. add some advice around the a "private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException" method
This article may also help: http://java.sun.com/developer/technicalArticles/Programming/serialization/
I think the idea of serializing a bean and then forcing a reinjection of dependencies is not the best architecture.
How about having some sort of ProcessWrapper bean instead which could be a singleton. It would be injected with the Repository and either manages the deserialization of the Process or has a setter for it. When a new Process is set in the wrapper, it would call setRepository() on the Process. The beans that use the Process could either be set with the new one by the wrapper or call the ProcessWrapper which would delegate to the Process.
class ProcessWrapper {
private Repository repository;
private Process process;
// getters, setters, etc.
public void do() {
process.do();
}
public void setProcess(Process process) {
this.process = process;
this.process.setRepository(repository);
}
}
Answering my own question: how I've solved the problem so far is to create a base class which serializes and deserializes using a cheap little proxy. The proxy contains only the name of the bean.
You'll note that it uses a global to access the Spring context; a more elegant solution might store the context in a thread-local variable, something like that.
public abstract class CheaplySerializableBase
implements Serializable, BeanNameAware {
private String name;
private static class SerializationProxy implements Serializable {
private final String name;
public SerializationProxy(CheaplySerializableBase target) {
this.name = target.name;
}
Object readResolve() throws ObjectStreamException {
return ContextLoader.globalEvilSpringContext.getBean(name);
}
}
#Override
public void setBeanName(String name) {
this.name = name;
}
protected Object writeReplace() throws ObjectStreamException {
if (name != null) {
return new SerializationProxy(this);
}
return this;
}
}
The resulting serialized object is 150 bytes or so (if I remember correctly).
The method applicationContext.getAutowireCapableBeanFactory().autowireBean(detachedBean); can be used to reconfigure a Spring-managed bean that was serialized and then de-serialized (whose #Autowired fields become null). See example below. The serialization details are omitted for simplicity.
public class DefaultFooService implements FooService {
#Autowired
private ApplicationContext ctx;
#Override
public SerializableBean bar() {
SerializableBean detachedBean = performAction();
ctx.getAutowireCapableBeanFactory().autowireBean(detachedBean);
return detachedBean;
}
private SerializableBean performAction() {
SerializableBean outcome = ... // Obtains a deserialized instance, whose #Autowired fields are detached.
return outcome;
}
}
public class SerializableBean {
#Autowired
private transient BarService barService;
private int value;
public void doSomething() {
barService.doBar(value);
}
}