Java 11 - Replace Spring #PostConstruct with afterPropertiesSet or using initMethod - java

I'm using spring applications which sometimes uses #PostConstruct for setup in code and tests
It seems that annotation will be excluded from Java 11:
Note that both #PostConstruct and #PreDestroy annotations are part of Java EE. And since Java EE has been deprecated in Java 9 and removed in Java 11 we have to add an additional dependency to use these annotations
Article suggest replacing all #PostConstruct with afterPropertiesSet method
I recommend you to change implementation from #PostConstruct annotation to implement org.springframework.beans.factory.InitializingBean interface.
Can I blindly replace it in all cases? or are there other considerations?
EDIT
As #JBNizet suggested, this maybe not a must or needed, as Spring doc suggest the opposite
We recommend that you do not use the InitializingBean interface, because it unnecessarily couples the code to Spring. Alternatively, we suggest using the #PostConstruct annotation or specifying a POJO initialization method.
EDIT 2
Another option is using initMethod:
With Java configuration, you can use the initMethod attribute of #Bean
#Bean(initMethod = "init")
public BeanOne beanOne() {
return new BeanOne();
}

Spring uses jakarta.annotation.PostConstruct. As a contributor in spring-cloud-kubernetes, I have used it and included it in that project numerous times. As a matter of fact we favor dropping InitializingBean.

Ref https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-postconstruct-and-predestroy-annotations
Like #Resource, the #PostConstruct and #PreDestroy annotation types were a part of the standard Java libraries from JDK 6 to 8. However, the entire javax.annotation package got separated from the core Java modules in JDK 9 and eventually removed in JDK 11. If needed, the javax.annotation-api artifact needs to be obtained via Maven Central now, simply to be added to the application’s classpath like any other library.

Related

Callbacks in bean lifecycle

I was just going through spring documentation for Lifecycle callbacks for a bean. For initialization callback the documentation recommends using #PostConstruct annotation instead of using the InitializingBean interface implementation as it couples code with Spring. Could someone please explain what they mean when they say coupling code with spring. I will share the link to the section i was going through here.
The #PostContruct annotation is not Spring-specific, but from Jakarta Annotations. This way, the core part of your code is not tied to Spring specifically, but could also work in a non-Spring environment, including any Jakarta EE implementation (see "Certified referencing runtimes" in the article), for example, GlassFish or WildFly.
Here is the relevant Javadoc from the Jakarta documentation: PostConstruct.
InitializingBean is pure Spring and will only work in Spring. #PostConstruct is ordinary Java 1.8. Sadly, from 9 it's dependent on javax.annotation:javax.annotation-api:1.3.2

Annotations from javax.xml.bind.annotation not working on payara 5 jdk 11

I'm using docker payara/server-full:5.2020.5-jdk11 image. I deployed the java ee app built with JDK 11. I have some DTOs, in which I have annotations like:
#XmlJavaTypeAdapter(DateTimeAdapter.class)
private Date creationDate;
private SomeEnum enumm;
#XmlEnum
public enum SomeEnum {
#XmlEnumValue("U")
USER;
}
and these annotations are not working (while making rest requests). There is no error in runtime. Annotations are just ignored. I tested adding ie throw exception in adapter and nothing happened.
I read about that in JDK 11 this package is excluded, and I also added the recommended dependencies to the pom, but still no difference. And, as I said, I have no error.
I need to mention, that i'm making the migration from payara 4.
I think that my problem is related to those topics:
JSON Binding #JsonbTypeDeserializer annotation ignored on enums?
Glassfish 5 ignores JAXB #XmlJavaTypeAdapter annotation?
How do I configure Glassfish 5 to use Moxy as the default Provider?
For now I decided to use:
#JsonbDateFormat
// and
#JsonbTypeAdapter
as a replacement.

Spring Meta-Annotations

Does anybody know what Spring JAR (and where to find it!) contains the functionality for Spring's so-called "meta-annotations". As this article shows, these cool "new" (well, sorta) constructs allow code like this:
#Service
#Scope("request")
#Transactional(rollbackFor=Exception.class)
#Retention(RetentionPolicy.RUNTIME)
public #interface MyService {
}
#MyService
public class RewardsService {
…
}
Basically, I have a Swing app that does not currently use Spring. I have a sudden requirement change that would be made supremely-easier if I could use these annotations.
So I'm just looking for the smallest, minimally-invasive Spring JAR where this functionality can be found. If absolute-need-be, I can use the entire Spring JAR, but it would be a very heavy-handed solution. It would be nice if Spring released a smaller JAR with smaller-scope functionality.
I'm browswing Maven Repo and see spring-core which contains a package called:
org.springframework.core.annotation
But upon inspection of the API docs it doesn't seem to be what I need...
Ancillary question: is it even possible to use these meta-annotations as standalone constructs, or do I have to use them along with, say, Spring DI or AOP or other major parts of the Spring framework?
Thanks in advance!
The annotations you want will be with the jar it is related to. For instance, the annotation org.springframework.transaction.annotation.Transactional will be in the spring-transactions artifact.
Meta-annotations are not really different from regular annotations other than the fact that Spring now detects Annotations on annotations whereas it didn't before. Whether annotations "work" or not depends on what is looking for them (in this case something in the Spring context).
For further reading see Annotation-based container configuration in the Spring framework reference.
There is project on github which is trying to provide meta-annotation functionality.
https://github.com/dblevins/metatypes/

JSR-299 (CDI) configuration at runtime

I need to configure different #Alternatives, #Decorators and #Injectors for different runtime environments (think testing, staging and production servers).
Right now I use maven to create three wars, and the only difference between those wars are in the beans.xml files. Is there a better way to do this? I do have #Alternative #Stereotypes for the different environments, but even then I need to alter beans.xml, and they don't work for #Decorators (or do they?)
Is it somehow possible to instruct CDI to ignore the values in beans.xml and use a custom configuration source? Because then I could for example read a system property or other environment variable.
The application exclusively runs in containers that use Weld, so a weld-specific solution would be ok.
I already tried to google this but can't seem to find good search terms, and I asked the Weld-Users-Forums, but to no avail. Someone over there suggested to write my own custom extension, but I can't find any API to actually change the container configuration at runtime.
I think it would be possible to have some sort of #ApplicationScoped configuration bean and inject that into all #Decorators which could then decide themselves whether they should be active or not and then in order to configure #Alternatives write #Produces methods for every interface with multiple implementations and inject the config bean there too.
But this seems to me like a lot of unnecessary work to essentially duplicate functionality already present in CDI?
edit
Ok, I realized I'm a bit stupid... of course it is possible to add stereotypes and inteceptors at runtime using the CDI extension API:
void beforeBeanDiscovery(#Observes BeforeBeanDiscovery bbd) {
bbd.addInterceptorBinding(...)
bbd.addStereotype(...)
}
But what I didn't find was an API to add a decorator. The only thing I found was to activate all #Decorators in the beans.xml, then observe
public <T> void processAnotated(#Observes ProcessAnnotatedType<T> event)
and call
event.veto()
if I don't want a #Decorator to be active.
You might want to take a look at JBoss Seam, specifically the Solder sub-project.
It allows dependency driven CDI resolution, so that certain beans are only available if other beans or resources are available. (Class A if "dataSource" is available, Class B if "entityManager" is available)
Since it's open source, you can also take a look at how they wired that together, and use that knowledge as a basis for writing your own extension if needed.
If you're using JSF, I would highly recommend using SEAM-JSF as well, as it gets rid of the clunkiness of having two injection frameworks (JSF DI/CDI) and allows CDI beans in JSF scopes.

Annotation base configuration in standalone Java program

I was made aware with the annotation base configuration (the #Resource) feature in Java EE which I really like. Then I noticed that the annotation was actually part of Java SE.
So I wonder if I can use it with Java SE. I can surely use the annotation in a standalone program but I am find how to actually configure it. All the examples I found involve creating a Java EE configuration file. Can any one give me a confirmation (or give me a reference to one) that it can be used outside of Java EE environment? and how to do that?
Annotations have specific purposes and can only be used for those purposes. So Java EE annotations will in most cases have no function outside Java EE. But for instance jUnit and JPA annotations should work in a Java SE applications. You can also roll your own if you feel like it.
I'm thinking the same thing. Something must process annotations--this is what Spring does, but currently I'm not using Spring.
It wouldn't be too difficult to add custom annotation processing to handle the #Resource, #PostConstruct and #PreDestroy annotations (It would probably be a few dozen lines of code) but at some point you gotta think "Well, Spring is already doing all that and a heck of a lot more".
They are also implemented by Tomcat for WebServices, so you can just use them but only on properly configured #WebService classes.

Categories