Spring Boot REST controller classpath - rest

We're starting a Spring Boot app with gradle bootRun which triggers the x.Application class which has the annotation #SpringBootApplication. After starting we can access REST services in the x package but can't access REST services in other packages. How can you configure the classpath accordingly?

Assuming your x package is something like com.example.mybootapp and your main Application.class is inside x package then you need to add this
#SpringBootApplication
#ComponentScan({"com.example.mybootapp","com.example.someother","one.more.pack"})
on your main Application.class method or Configuration file.
#SpringBootApplication itself consists of #Configuration #EnableAutoConfiguration #ComponentScan annotations, so #ComponentScan default the basePackge (i.e. packages to scan) to the package of the main Application.class and that is why Spring is unable to detect your other #Controlers which are outside of main package.
If you structure your code as suggested above (locating your application class in a root package), you can add #ComponentScan without any arguments. All of your application components (#Component, #Service, #Repository, #Controller etc.) will be automatically registered as Spring Beans.
Refer this document on how to structure your code.

Related

How to load selected beans from external library in micronaut

I'm used to creating custom Spring Boot based libraries with a number of different beans per library. A target Spring Boot app then would use #Import to make a subset of those Beans available w/out importing all of the beans from an external library. An external library would also include spring integration tests (i.e. #SpringBootTest).
I'm trying to replicate this functionality in Micronaut. I've created an external library using 'io.micronaut.library' gradle plugin. It also contains some micronaut integration tests (i.e. #MicronautTest).
Per https://docs.micronaut.io/latest/guide/#beanImport I expected none of the beans to be imported by default. However, I've noticed that a class annotated with #Singleton was imported by default. I suspect this is due to its inclusion in the META-INF/services/io.micronaut.inject.BeanDefinitionReference within the library jar. If I remove META-INF/services/io.micronaut.inject.BeanDefinitionReference from the jar manually then none of the beans are imported by default and I can use explicit #Import to import what is needed.
The package of the library is com.some.micronaut.http while application package is com.some.somethingelse so the namespaces do not match. Both the library and the application are written in Kotlin.
Is there a way to control which beans are imported from an external library? Or can I control which bean references are included in META-INF/services/io.micronaut.inject.BeanDefinitionReference?
Here is a relevant build.gradle portion from the external library:
plugins {
id("org.jetbrains.kotlin.jvm") version "${kotlinVersion}"
id("org.jetbrains.kotlin.kapt") version "${kotlinVersion}"
id("org.jetbrains.kotlin.plugin.allopen") version "${kotlinVersion}"
id 'io.micronaut.library' version "3.1.1"
}
dependencies {
implementation("io.micronaut:micronaut-http-client")
implementation("io.micronaut:micronaut-jackson-databind")
//test
testImplementation 'io.micronaut.test:micronaut-test-junit5'
testImplementation 'org.junit.jupiter:junit-jupiter-params'
//wiremock for http client tests
testImplementation 'com.github.tomakehurst:wiremock-jre8:2.32.0'
}
I'm flexible about usage of io.micronaut.library plugin but I do need to be able to run #MicronautTest as part of the library build.
For now, I've removed META-INF/services/io.micronaut.inject.BeanDefinitionReference from the library jar explicitly in my build.gradle:
jar {
exclude('META-INF/services/io.micronaut.inject.BeanDefinitionReference')
}
and then used #Import in my application to explicitly import the desired components. I've also submitted an enhancement request.

#ApplicationScoped Bean Not Eagerly Instantiated on Wildfly 16

I have an #ApplicationScoped bean that I want to be instantiated on application startup (see sample code below). I've registered for the servlet context initialization event but the init method is never invoked. The FactoryLocator is contained in a jar within my war's WEB-INF/lib directory. This same code was working on Wildfly 9 but no longer works after upgrading to Wildfly 16.
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Initialized;
import javax.enterprise.event.Observes;
import javax.servlet.ServletContext;
#ApplicationScoped
public class FactoryLocator {
public FactoryLocator() {
System.out.println("In the constructor.........................");
}
private void init(#Observes #Initialized(ApplicationScoped.class) ServletContext sc) {
System.out.println("Invoking the event observer method..................");
}
}
One workaround I discovered was to extract the contents of the jars in my war's WEB-INF/lib/ directory to my war's WEB-INF/classes directory. When I did this my FactorLocator bean was instantiated successfully. I'd prefer not to have to do this.
After debugging through the war's deployment, I noticed that the ServletContext is initialized before all the beans in the war's lib directory are processed (org.jboss.weld.bootstrap.BeanDeploymentModules:processBeanDeployments). The war's module is not aware of all observers until all the beans are processed. However, the ServletContextEvent is fired before all the observers are known.
Should this happen that ServletContext is created before all observers are known about? I've debugged one of the Wildfly QuickStart applications and the ServletContext isn't created until all bean deployments are processed and the code below is executed successfully. Is the order in which this happens supposed to be guaranteed?
Just in case anyone else has seen the same issue. Upgrading to Wildfly 21.0.1.Final resolved the issue for me.

Using Spring MVC 4, when I add Spring Security 3.2 to pom I get ASM ClassReader failed to parse class file error

I am using Java 8 in eclipse. Could the issue be that spring security does not support Java 8 as of yet?
12:13:44.226 [localhost-startStop-1] ERROR org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidate component class: file [C:\dev\workspace_professional_web_development\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\movierental\WEB-INF\classes\com\hemswortht\movierental\annotation\ReleaseYearConstraint.class]; nested exception is org.springframework.core.NestedIOException: ASM ClassReader failed to parse class file - probably due to a new Java class file version that isn't supported yet: file [C:\dev\workspace_professional_web_development\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\movierental\WEB-INF\classes\com\hemswortht\movierental\annotation\ReleaseYearConstraint.class]; nested exception is java.lang.IllegalArgumentException
and ReleaseYearConstraint.java...
package com.hemswortht.movierental.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.ReportAsSingleViolation;
import com.hemswortht.movierental.validator.ReleaseYearConstraintValidator;
#Target({ ElementType.TYPE })
#Constraint(validatedBy = ReleaseYearConstraintValidator.class)
#Retention(RetentionPolicy.RUNTIME)
#Documented
#ReportAsSingleViolation
public #interface ReleaseYearConstraint {
String message() default "You have specified invalid search input parameters.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
This all boils down to dependencies version management in your build.
I suggest you to take a look at the various solutions Spring offers for that:
Spring Framework BOM, for managing spring-framework versions efficiently
Spring IO platform BOM if you want to get version management for spring-framework, spring portfolio projects (so spring security) and even third party dependencies
Note that changing the order of dependencies in your pom does not solve completely your problem - you'd better add dependency exclusions.
I figured it out! So basically you must use Spring 4 if you are using Java 8. Spring Security 3.2 is compatible with Spring 4 so that's ok.
so where did I go wrong?????
You need to make sure the Spring Security 3.2 dependencies COME AFTER the Spring 4 dependencies in the pom. Otherwise all spring versions get resolved to 3.2.6 !!! Doh.

GWT ServiceLocator with multi-module maven project

I've a multi-module GWT project and I'd like to use ServiceLocators. I have 3 modules:
"client" depends on shared
"shared"
"server" depends on shared
I wrote the ServiceLocator like this:
public class TreeServiceLocator implements ServiceLocator {
public Object getInstance(Class<?> clazz) {
return new TreeService();
}
}
and placed this class in the "shared" module because ServiceLocator has the package com.google.gwt.requestfactory.shared. However, when I compile this throws an error because TreeService is implemented in the "server" module since I need it to return beans from the server and interact with Spring, etc.
In which module should I implement the TreeServiceLocator? Also, maven will throw a circular dependency error if I try to include "server" from the "shared" module.
Thank you!
Place the TreeServiceLocator in the server package, and use a #ServiceName annotation instead of #Service. These annotations have the same effect, but the former uses string literals instead of class literals. This will avoid problems with the GWT compile if the server types aren't available on the classpath of the GWT compiler.

Trouble with Aspectj load-time-weaving when using EclipseLink JPA in Spring dm Server 1.x

I am attempting to get EclipseLink JPA working inside the Spring dm Server OSGi environment.
Relevant frameworks and libraries downloaded from the Spring Enterprise Bundle Repository include:
dm Server 1.0.2.SR02
AspectJ Runtime 1.6.3
AspectJ Weaver 1.6.3
Spring Framework 2.5.6.A
Eclipse Persistence 1.1.0
Javax Persistence API 1.99.0
I followed the same structure as presented in the PetClinic-1.5.0 example for setting up EclipseLink JPA. Everything works until lazy-fetching is enabled (which requires proxied objects).
Once lazy-fetching is enabled, the following error suggests that load-time-weaving is not working correctly.
---- (truncated for readability)
Exception [EclipseLink-60] (Eclipse Persistence Services - 1.1.0.r3634): org.eclipse.persistence.exceptions.DescriptorExcep tion
Exception Description: The method [_persistence_setcustomer_vh] or [_persistence_getcustomer_vh] is not defined in the object [net.fractech.fds.backoffice.Job].
Internal Exception: java.lang.NoSuchMethodException: net.fractech.fds.backoffice.Job._persistence_getcu stomer_vh()
Mapping: org.eclipse.persistence.mappings.OneToOneMapping[customer]
Descriptor: RelationalDescriptor(net.fractech.fds.backoffice.J ob --> [DatabaseTable(JOBS)])
This shows that the _persistence_getcustomer_vh() and _persistence_setcustomer_vh() methods were not automatically weaved into the Job domain object.
Questions
1.) How do I determine if load-time-weaving is actually working; moreover, how do I log which load time weaving agent and weaver was started? How do I pass switches to this weaver to have it output debugging information?
I assume I started load-time-weaving with <context:load-time-weaver aspectj-weaving="on" />
2.) Many searches have revealed that I do not need to pass the -javaagent parameter to the jvm when using dm Server. Is this correct?
3.) I have assured that my domain objects in another bundle have access to the eclipse persistence classes by asserting com.springsource.org.eclipse.persistence;version="[1.1.0,1.1.0]";import-scope:=application in my eclipselink bundle and including all application bundles within a PAR. Are there any other configurations needed to enable EclipseLink JPA in Spring dm Server?
I had similar problems. First try setting eclipselink.weaving.lazy=false, or eclipselink.weaving=false if that doesn't work. I had to set the latter.
If you would like to refer to the setup I am using to see if it applies to you, I have a post about it on my site.
It is better to use Equinox Waving Springwaver
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
...
<property name="loadTimeWeaver">
<bean class="org.eclipse.equinox.weaving.springweaver.EquinoxAspectsLoadTimeWeaver"/>
</property>
</bean>
You don't need to use -javaagent option then.
You can find working examples with JPA and EclipseLink here http://code.google.com/p/springdm-in-action/ (see Chapter 7).
I have tried to use EquinoxAspectsLoadTimeWeaver into JPa context (with EclipseLink) but it doen't transform the model classes if your EquinoxAspectsLoadTimeWeaver bean declaration is not done into the same bundle than Model bundle.
EquinoxAspectsLoadTimeWeaver transform class ONLY for the classes stored into the bundle wich declare EquinoxAspectsLoadTimeWeaver.
I have tried the sample http://code.google.com/p/springdm-in-action/ (see Chapter 7) (thank for this sample Lukasz). The declaration of EquinoxAspectsLoadTimeWeaver avoid having the error
Caused by: java.lang.IllegalStateException: Cannot apply class transformer without LoadTimeWeaver specified
But Model classes are not transformed (woven). Weaving into EclipseLink manage for instance lazy mode. For instance if you set into the sample model Contact lazy mode like this :
public class Contact {
...
#Column(name="last_name")
#Basic(fetch=FetchType.LAZY)
private String lastName;
you will notice that lazy loading is not applied because Model Contact class is not wowen.
Regards Angelo