Spring Annotations in XPages Java classes - java

I'm trying to use Spring annotations in Domino XPages Java classes. Spring works when I'm defining beans in the configuration file. However I fail to use the annotations.
To illustrate the problem, I have created two simple empty classes annotated with #Component annotation - com.geo168.a.B (#Component public class B {}) and com.geo168.a.C (#Component public class C {})
The first one I have created in Eclipse, packed and added to the application in a jar. The second one I add directly in Code/Java section.
I add a component-scan tag in the configuration file: <context:component-scan base-package="com.geo168.a"/> and try to instantiate the classes:
ApplicationContext ctx = new ClassPathXmlApplicationContext(SPRING_CONFIG);
// class defined in the jar, works ok
com.geo168.a.B b = ctx.getBean(com.geo168.a.B.class);
// class defined in Code/Java, throws exception
com.geo168.a.C c = ctx.getBean(com.geo168.a.C.class);
I get an error: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.geo168.a.C] is defined
Spring has found the annotated class only in the JAR file. It works if I add the bean explicitly to the configuration file:
<bean class="com.geo168.a.C"/>
A similar post: Is possible to add annotation #ManagedBean in XPages? seems to address only the particular JSF annotations (that do not work, because they are not implemented).
In the Spring documentation: http://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/beans.html#beans-scanning-autodetection I find a note: The scanning of classpath packages requires the presence of corresponding directory entries in the classpath. When you build JARs with Ant, make sure that you do not activate the files-only switch of the JAR task.
Could this be somehow related? I do not know in what form Domino deploys the classes internally.

Related

Consider defining a bean of type in your configuration in spring boot when using Spring JpaRepository

Good day,
I am doing a Spring Boot Application in my Eclipse IDE. When I right click on my SpringBoot Application file and run as Java application, I hitting error as follow:
APPLICATION FAILED TO START
Description:
Field tutorialRepository in com.utility.tool.ToolApplication required a bean of type 'com.utility.tool.repository.TutorialRepository' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.utility.tool.repository.TutorialRepository' in your configuration.
Then I found that I forget to include the spring boot starter data jar. Hence, I add the following code in my build.gradle and it finally run correctly:
implementation 'org.springframework.boot:spring-boot-starter-data-jpa:2.7.5'
Then I right click my project and export jar as runnable jar, and then try to run it by java -jar my.jar, and it hit back the error.
I open the jar in JdGui, and found that the spring-boot-starter-data-jpa-2.7.5.jar is inside. May I know what is my mistake? My jar structure is something as follow:
The jar is in the list but is at bottom, thus not in my screen shot.
Check your SpringBoot annotations. You may be missing some #Service, #Repository, #Component annotations.

Define stereotype to use on different project

I have 2 java-ee (helidon-mp) projects (Lets say A and B), both share some logic which is encapsulated on a separate project/jar/dependency, the projects are similar yet not identical, to handle those differences I consider it would be a good idea to create a Stereotype which would allow me to specify when do I want to create/provide instances tuned for either A or B project. Given the shared dependency project creates beans it has its own beans.xml file, just as both of the projects that depend on it.
The problem
I would like to be able to specify the desired stereotype to use within the beans.xml file of each project, yet when I specify the stereotype at the project level, such configuration is not passed down to the dependency project; this throws an exception with a message similar to the following one:
WELD-001408: Unsatisfied dependencies for type NeededClassForAProject with qualifiers #Default
at injection point [BackedAnnotatedParameter] Parameter 1 of [BackedAnnotatedConstructor] #Inject public the.project.class.injecting.dependency.ProjectA(NeededClassForAProject)
at the.project.class.injecting.dependency.ProjectA.<init>(ProjectA.java:0)
When I define the stereotype within the dependency beans.xml everything works like a charm yet this causes that whenever I need to work with Project A I need to update (and rebuild) the dependency project changing its beans.xml indicating I want to use the configuration for A and same goes whenever I switch to working with project B
The question itself:
Is it possible to keep my configuration at the project level beans.xml and make the dependency project recognize such configuration from the parent project? how
The answer is here
where it clearly states:
By default, #Alternative beans are disabled. We need to enable an alternative in the beans.xml descriptor of a bean archive to make it available for instantiation and injection. However, this activation only applies to the beans in that archive.
From CDI 1.1 onwards the alternative can be enabled for the whole application using #Priority annotation.

Inject bean from a different folder

I have a project structure that looks like this:
In My Groovy folder contains a class marked with #Component that I Want to inject in another class inside the java folder. However spring can't find the bean to inject, when I move the class marked with #Component to the java folder it works fine. How can I make spring aware of the groovy folder?
You can use #ComponentScan at your Spring application (annotated with #SpringBootApplication) to scan components from other packages.
#ComponentScan(basePackages = "com.stackoverflow.other.package")
See https://www.baeldung.com/spring-component-scanning.

Spring-boot > implicitly auto register a 3rd party bean

This may be an impossible task, but here goes...
Is it possible to register a spring bean, by (ONLY) adding a jar to the classpath of a spring-boot application?
Scenario: I would like to create a non-intrusive plugin jar, which when imported into a spring-boot project's classpath, will automatically be picked up and provide a service (e.g. via a RestController).
Constraints
I don't want to change or reconfigure the existing spring-boot application (i.e. no additional scan paths or bean config).
I don't have any knowledge of the target spring-boot application's package structure/scan paths.
I guess I was hoping that by default Spring scan's its own package structure (i.e. org.springframework.** looking for the presence of database libs, etc) and I could piggy-back off that - I haven't had any luck (so far).
I've setup an example project in github, to further clarify/illustrate my example and attempts.
** Solution Addendum **
This bit that got it working, was to add the following file, which points to an #Configuration config file...
plugin-poc\src\main\resources\META-INF\spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.thirdpartyplugin.PluginConfiguration
I think in such cases you would try to add a spring auto configuration that is annotated with #ConditionalOnClass to be only evaluated if the given class is on the classpath. This class can register the bean and would just be evaluated if the conditional evaluates to true
Here is the relevant part of the spring boot documentation : Creating your own auto-configuration

Can I auto-discover jaxws:endpoints for beans.xml based on annotated #WebService classes / interfaces?

I created a cxf/spring project with:
mvn archetype:create -DarchetypeGroupId=org.apache.cxf.archetype -DarchetypeArtifactId=cxf-jaxws-javafirst
The resulting project has a HelloWorld.java interface annotated as a #WebService, and a HelloWorldImpl.java annotated with an endpointInterface=mypackage.HelloWorld.
There's a beans.xml file containing:
<jaxws:endpoint
id="helloWorld"
implementor="mypackage.HelloWorldImpl"
address="/HelloWorld" />
If I want to add more services, it looks like I'm expected to keep adding new endpoints in beans.xml. Since the classes are already annotated as #WebService, why can't it auto-discover any new services within some package / search path? Is there some way I can configure this project to do that?
Basically, I'm just trying to avoid repeating myself. The information is already going to be in the annotations so I don't want to have to edit additional files each time I add a service.
If I remove the jaxws:endpoint tag in beans.xml, and then mvn install tomcat:run, localhost:8080/myArtifactId just shows me a page saying there are not services defined.
When you use the CXF you should know that all the endpoints you added are managed by the CXFServlet that uses Spring context to find them out. beans.xml is a Spring context's config file. So if you remove the <jaxws:endpoint/> node from that file your Spring context and hence the CXFServlet will have no way to find your service endpoints.

Categories