Spring conditional annotations (NOT #Conditional) - java

Can you make Spring annotations conditional?
I mean for example having the following method:
#CachePut(value = "latestALLFXRatesCache", key = "#definition.key")
public AssetValueSnapshot refreshCacheLatestFXValue(DataSource definition) {
AssetValueSnapshot assetsnap = getLatestFXValueSnapshot(true,definition);
}
Can I make the #Cacheput annotation conditional (preferably with another spring annotation)?
For example:
if #Profile("XXX") or #Conditional(XXX)
#Cacheput
else
#Cacheable
public AssetValueSnapshot ...
Regardless whether this makes sense and knowing that #Profile and #Conditional are not made for this, can I do what I want with annotations or is there some other way in Spring?
Edit after comments:
I'm talking about a broader scope than just a specific annotation (cacheput in this case). I'm wondering if there is an annotation/other way that makes any annotation conditional; regardless of that annotations own conditional behavior.

Related

Accessing CDI from simple objects?

Assume I have a configuration class accessible via the stock CDI that defines some application-wide parameters:
#ApplicationScoped
class AppConfig {
public double getMaxAllowedBrightness() { ... }
};
And I have a simple class for my data objects:
class LightSource {
double brightness;
...
boolean isValid() {
double maxAllowedBrightness = ...; // Somehow use AppConfig#getMaxAllowedBrightness() here
return brightness <= maxAllowedBrightness;
}
}
How can my data object access the single AppConfig instance?
Somehow I hate the idea of autowiring AppConfig into every single data object (there are lots of them). Is there any other way to get access to AppConfig in the above example from my data object?
What's the best pattern to use here?
The simplest example is a runtime lookup akin to:
import jakarta.enterprise.inject.spi.CDI;
CDI.current().select(cls).get();
With cls being the class that you're looking up. (Note the package name, this is the latest version of CDI 2.x in the new jakarta namespace, the original is in javax.)
It gets more detailed from there, but that's the gist of it.
Note, that semantically there's little difference between autowiring something and doing a runtime lookup, especially for something mostly static at the instance level. It's still a dependency. You still have to touch the code of the classes to pull it off.
A nice thing of relying on the autowiring is that you can disable it situationally, and the class reverts to a simple bean, that you can do with what you will. Coding in the lookup, it's a little bit more than that.
Dynamic lookup is more for special circumstances.
On my current project, our team has been doing this using the #Value annotation. In our case, we have all the properties in a properties bean, which I'll call mainAppConfiguration. The bean is populated from a properties file like main-app-config.properties (which was read into the bean with a Properties prop = new Properties().load(mainAppConfigFilePath) method.
Assuming you have something like that set up, then we inject the properties into the classes that need them using a little SpEL magic something like:
private Integer refreshRateSeconds;
#Value("#{ mainAppConfiguration.getProperties()['funny-property-base-name.refreshRateSeconds'] }")
public void setRefreshRateSeconds(Integer refreshRateSeconds) {
if (refreshRateSeconds == null) {
throw new IllegalArgumentException("Required config property 'funny-property-base-name.refreshRateSeconds' was not found"));
}
this.refreshRateSeconds = refreshRateSeconds;
}
Baeldung has examples (without defaults) and more with defaults.

Creating and using annotation in java

I am reviewing open source spring projects. I am confused about the use of annotations around here. I want to ask to clarify this.
#Target(ElementType.METHOD)
#Retention(RUNTIME)
#Bean
public #interface Merge {
#AliasFor("targetRef")
String value() default "";
#AliasFor("value")
String targetRef() default "";
Placement placement() default Placement.APPEND;
int position() default 0;
Class<MergeBeanStatusProvider> statusProvider() default MergeBeanStatusProvider.class;
boolean early() default false;
}
An annotation has been created here named Merge. It has different parameters and default values.
#Configuration
public class LocalConfiguration {
#Merge(targetRef = "mergedList", early = true)
public List<String> blLocalMerge() {
return Arrays.asList("local-config1", "local-config2");
}
}
And this is usage of #Merge annotation in any class I choosed randomly.
When I examined the code, I could not find any class related to the implementation of Merge annotation. By the way, this problem I'm having isn't just about this annotation. Almost all the annotations I have examined are used without being implemented in any way.
I think I will understand the others if we start from this annotation.
What does this anotation do? What kind of message does it give to the place where it is used. How does the application understand what that annotation does in runtime without being implemented anywhere.
Thanks.
Annotations don't have implementations. They are processed by external classes or tools depending on the RetentionPolicy. In this case, the Merge annotation has Runtime retention so it will be available via reflection once the class is loaded. At runtime any interested party (in this case I assume the Spring Framework) can use getAnnotations on your LocalConfiguration class to detect the Merge annotation and take whatever action that needs to be taken. The possibilities are really up to the framework that defined the annotation. A lot of Spring injection works like this with annotations but they are also used by many other frameworks such as Hibernate, Jersey, etc. The main idea is that annotations act as markers on specific code points to be used by an external entity at a later point.

Java annotations: pass value of annotation attribute to another annotation

I have interface Resource and several classes implementing it, for example Audio, Video... Further, I have created custom annotation MyAnnotation with Class type param:
#MyAnnotation(type = Audio.class)
class Audio {
...
}
#MyAnnotation(type = Video.class)
class Video{
...
}
In some other place in code I have to use Interface Resource as a returned type:
public class Operations<T extends Resource> {
....
#OtherAnnotation(type = Audio.class (if audio), type = Video.class (if video) )
T getResource();
....
}
The question is how to appropriatelly annotate annotation #OtherAnnotation depending of what kind of Resource type will be returned ?
What you are asking is for dynamic values for annotation attributes.
However annotations can only be set at compile time which is the reason why their values can only be compile time constants. You may only read them at runtime.
There was a similar question in which someone tried to generate the annotation value , it's answer explains why there is no way to dynamically generate a value used in annotation in a bit more detail. In that question there was an attempt to use a final class variable generated with a static method.
There are annotation processors which offer a bit more flexibility by handling placeholders. However i don't think this fits your case, as you want the dynamic values at runtime.
This answer refers to spring's use of the expression language for the Value annotation in which the placeholder (#Value("#{systemProperties.dbName})") gets overrided with the data from one of the property sources defined ( example in spring boot )
In any case, you will have to rethink your architecture a bit.

Java - Custom/standard validation with Annotations

I'm using annotations in a project. The thing is i'm making custom validation that (partly) depends on annotations. I'm also making own annotations, but I want to use as much as I can from the JSR 303 standard.
to check if a field 'passes' the annotation constraints i've written some methods. Example:
static boolean isNotNullValid(Field f){
boolean valid = true;
if(f.isAnnotationPresent(NotNull.class)){
Object o = ObjectGetter.getFieldValue(f);
if(o==null){
valid = false;
}
}
return valid;
}
It's quite a lot of work to do this type of validation for all annotations. Is there some method i'm missing, like .isValid() ? I mean, of course, for the standard annotations.
Thanks in advance
You're not supposed to code that by yourself. You should instead rely on an implementation of the JSR, for example Hibernate Validator. The Validator it implements allows getting a set of constraint violations based on the annotations on the bean.

Howto inject simple config parameters to beans using Guice?

Is there a simple way to inject simple primitive type parameters (string and int) to the beans?
What i need is to find the guice equivalent of something like this from spring.xml:
<bean id="aBean" ...>
<property name="fieldName" value="aStringValue"/>
<property name="anotherFieldName" value="123"/>
</bean>
The values could be constructor injected, field injected or method injected, but i don't want to use separate named annotation or factory or provider for every value that i need to pass to the bean.
EDIT: my solution
Here is what i finally came to. I think it is closest to what i'm looking for, but any improvements would be welcome.
I found that in the module, i can declare a provider method and use it to set any properties i need:
MyModule extends AbstractModule{
...
#Provides #Named("testBean") MyTestBean createTestBean(MembersInjector<TestBean> mi){
TestBean test = new TestBean();
mi.injectMembers(test);
test.setFieldName("aStringValue");
test.setAnotherFieldName(123);
return test;
}
...
}
The good point is that the Provides method replaces the bind() for the bean and this way the actual line count doesn't increase much.
I'm still not 100% sure about any side effects, but it looks promising.
There is a build in mechanism to inject properties.
Properties File:
name=jan
city=hamburg
Module
#Override
protected void configure() {
Names.bindProperties(binder(), properties);
}
then in your bean, just inject by Name
class Customer {
#Inject
#Named("name")
String name;
....
}
There are a couple different ways you could do this, including your way. The only drawback to using a Provider method is that it's essentially a hand-rolled factory that you have to remember to maintain. (And in this specific case, you're also not getting the benefits of constructor injection).
Absent a Provider method, you have to use a binding annotation of some kind. If #Named won't work for you, then you'd need to create an annotation for each binding.
bindConstant().annotatedWith(FieldName.class).to("aStringValue");
public SomeClass {
public void setFieldName(#FieldName String fieldname) {}
}
In some cases this might require a 1-to-1 annotation per primitive/String instance to be bound. But I try to make my annotations somewhat orthogonal to the actual instance being described, preferring instead to use the annotation to describe the relationship between the bound objects and the injection points.
It's not always possible, but a whole group of related primitives could then potentially be described by a single binding annotation, as long as each primitive type is only used once in the set. So, this could hypothetically work:
bindConstant().annotatedWith(MyAnnotation.class).to("aStringValue");
bindConstant().annotatedWith(MyAnnotation.class).to(123);
Parenthetically, I'm curious why you can't used #Named annotations on the property, but you can use them on the injected bean?

Categories