Using Java validator for SpringBoot properties with #Value annotation - java

Does anybody know if it's possible to use custom ConstraintValidator for SpringBoot properties with #Value annotation?
Something like this:
#Component
#Validated
public class TestClass {
#Value("${test.property}")
#ValidValue(className=ValidValueValidator.class)
private String testProperty;
}

what's your mean how to make #Validated Take effect?
u can register a BeanValidationPostProcessor bean
or if your want use custom ConstraintValidator
see Majutharan Majutharan comment

Related

Spring Boot - Cannot read application.yml values from instantiated object

I'm trying to read some setting values from application.yml using the #ConfigurationProperties annotation.
An instantiated object of the class TestClass uses the properties class, so I added the #Configurable annotation, but the properties always be null and it causes NullpointerException.
The properties class:
#ConfigurationProperties
#Getter
#Setter
public class Properties {
private String setting;
}
And the object which uses the properties:
#Configurable
public class TestClass{
#Autowired
private Properties properties;
void print(){
System.out.println(properties.getSetting());
}
}
If I call the print method, NullPointerException will be occurred:
TestClass testClass = new TestClass();
testClass.print();
Am I missing something?
Short Answer:
Find the class that is annotated with #SpringBootApplication and add there also the annotation #EnableConfigurationProperties(Properties.class)
#SpringBootApplication
#EnableConfigurationProperties(Properties.class)
public class ServiceLauncher {
Explanation:
#ConfigurationProperties does not register the class that brings this annotation as a spring bean. It is only used so that Spring can read the properties with some meta configured information (ex prefix = "some.prop.prefix").
If you wish to use this class as a spring bean (ex via #Autowired) you need to combine the above annotation with #EnableConfigurationProperties which then says to spring that this class must become a spring bean.
Another workaround:
You could also instead just use the #Component on the Properties class and that would be enough without the need of #EnableConfigurationProperties but the later is better practice to be used.
#Component
#ConfigurationProperties
#Getter
#Setter
public class Properties {
Edit: After clarrified in the comments there is also another mistake in this code. You should replace #Configurable with #Configuration. The first one does not create a spring bean on the class that is placed!

MapStruct with Spring Boot, annotate generated classes with custom annotation

Is there possibility, to annotate class generated by MapStruct, with custom annotation? Currently Im using MapStruct with componentModel defined as "spring", like:
#Mapper(componentModel = "spring")
public interface MyMapper {}
For this interface, class is generated by MapStruct:
#Component
public class MyMapperImpl implements MyMapper {}
So I can easily inject it. What I want to do, is to annotate generated class with org.springframework.context.annotation.Profile annotation, so my generated bean will be in force only if specific profile is defined, is there possibility to inject such annotation, #Profile("dev"), to generated class somehow? I was thinking about org.mapstruct.DecoratedWith annotation, but I didn't make it working for me
This is currently not possible with the official API. This question is similar to mapstruct/mapstruct#1427.
However, there are 2 options that you can try to make it work.
Option 1 (annotate Mapper)
You can try to annotate MyMapper with the #Profile annotation, I am not sure whether Spring searches up the inheritance tree and in interface or not
Option 2 (use internal API)
MapStruct has the ModelElementProcessor that it used to add the #Component annotation. The one for Spring is SpringComponentModelElementProcessor.
You can provide your own componentModel (spring-dev for example) that would add the #Profile annotation to the generated mapper.

Multiple instances of a bean Spring

I have a config file in spring which I want to define a constructor parameter for each instance of a particular #Component that I have in spring. How can I do that?
#Component
public class MyComponent {
public MyComponent(String config) {}
}
and in my application.yml I want to define something like this:
myconfig:
- config1
- config2
- config3
I would like to make spring create one instance per config entry in the application.yml. Is that possible?
Thanks
There's no way to do this automatically with Spring. You would have to define the beans individually probably by subclassing as #Mick suggested. Firstly, remove the #Component annotation from the base class:
public class MyComponent {
public MyComponent(String config) {}
}
Create however many extensions of this you require as #Components for each config: e.g.:
#Component
public class MyComponentConfig1 extends MyComponent {
public MyComponentConfig1(#Value("myconfig.config1") String config) {
super(config);
}
}
Where the values are injected into your constructor for you by Spring when registering the beans.
You want to create 3 beans with one annotation? Not possible as far as I know. Why not create 3 subclasses and pull in the configuration values with #Resource annotations?
And btw: you must provide a default constructor, because that is the one being called.

Customised annotation in spring

I have seen few examples where customized annotations were used. example
#SimpleAnnotation
class SampleBean {
#SimpleAnnotation
public String getName() {
return "AAA";
}
public void setName(String name) {
}
public int getHeight() {
return 201;
}
}
#Target( { ElementType.METHOD, ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
#interface SimpleAnnotation {
}
Can anyone tell why we use this?
Spring supports for many Annotation the concept of "meta-annotation". (I am not sure if it is for all.)
This mean that you can build your own annotation and annotate the annotation with one of springs "core" annotations.
For example:
#Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
#Service
public #interface MyService {
}
Then you can use this annotation instead of #Service. (Btw: #Service, #Repository, #Controller use the same technique to "inherit" from #Component)
One example that make heavy use of this is "inherit" from #Qualifier.
For an example and some explanation have a look at Spring Reference Chapter: 3.9.3 Fine-tuning annotation-based autowiring with qualifiers (The Example with #Genre is at the end of the chapter.)
One very usefull construct that can be done with that technique is, that it enables you to combine several Annotations to a (in your use case) more meaning full. So instead of writing at every class of some type allways the same two annotations, for example: #Service and #Qualifiyer("someting") (the org.springframework.beans.factory.annotation.Qualifier). You can create your custom annotation that is annotated with this two annotations, and then use in your beans only this one custom annotation. (#See Avoid Spring Annotation Code Smell Use Spring 3 Custom Annotations)
If you want to see how powerfull this technique can be use, you can have a look at Context and Dependency Injection Framework.
Question from the comment:
The #interface also has some variables defined inside it, what does that signify?
The Annotations (defined by #Interface) work a bit like beans. This Fields are the properties that can/must be define if you use the annotations. The values can be later on be read via reflection API.
For example the #Controller Annotation in Spring:
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Component
public #interface Controller {
String value() default "";
}
The field with name value is that field that can be used without explicit name it: (#Controller("myUrl") is the same #Controller(value="myUrl"))
You can create your own meta-annotations that collect several other Spring annotations to reduce meta-boilerplate in your code:
#Service
#Scope(value = "prototype")
#Transactional(readOnly = true, rollbackFor = RuntimeException.class)
public #interface ReadOnlyService {}
And then you can simply write:
#ReadOnlyService
public class RoleService {
}
Spring will find the #ReadOnlyService and semantically replace it with:
#Service
#Scope(value = "prototype")
#Transactional(readOnly = true, rollbackFor = RuntimeException.class)
public class RoleService {
}
Of course having custom annotations pays of when you have tons of services annotated with the same set of Spring annotations that can be replaced with one, well named annotation.
Examples taken from: Avoid Spring Annotation Code Smell: Use Spring 3 Custom Annotations
Custom annotations do not do anything on their own. They are simple markers in code. Their real power comes from tools that look for specific annotations. Like some of the other answers mention, Spring has several uses for annotations and now mechanisms for defining your own component types. Pretty neat. Another example, a few weeks ago I used AOP and a few custom annotations to provide simple method level result caching. Now that I have the caching engine in place, and the appropriate AOP hooks defined, if I want to cache a method, I simply add that annotation. Some people simply use the annotations as fancy metadata to improve readability.
At the end of the day, they are a fairly simple tool that you can use for a great number of things.
The best part of using custom annotations is that you don't have to make any configuration, Spring will auto detect that these beans are service components and everything will work fine. Custom Annotations are a very small feature added in Spring but are very useful.For details take a look at this
http://java.dzone.com/articles/avoid-spring-annotation-code-smell-use-spring3-custom-annotations
Two options:
you need the #Component annotation on your custom annotation. That way you can use your custom annotation to mark classes as beans. In addition, you can add a default scope and other meta-information
qualifiers - you can use qualifier annotations (annotated with the #Qualifier meta-annotation) to distinguish between implementations of the same interface.
A common pattern is also to use annotations in AOP pointcuts. Not specifically Spring, but often employed when making use of Spring AOP.

How to insert property in Autodetected Component in Spring?

I am using #Service annotation of spring, so that my class should be autodetected by spring and made available for autowiring.But in my class, I need a property 'sqlmap'.If I had been using way of creating beans instead of auto-detection, I would have supplied that property using property tag in that bean..
So, is there any way I can inject my property in my class?Because unless that property is made available, spring will not be able to create bean of that class.
Your #Service class can "pull" a bean into a property using #Resource, e.g.
#Service
public class MyService {
#Resource (name="sqlMapClient")
private SqlMapClient sqlMapClient;
}
An alternative to #Resource is #Autowired, which will automatically select the target by type:
#Service
public class MyService {
#Autowired
private SqlMapClient sqlMapClient;
}
Try both, see which works best for you.

Categories