Integration - Apache Flink + Spring Boot - spring-boot

I'm testing the integration between Apache Flink and Spring Boot, to run them on IDE is fine, but when I tried to run on Apache Flink Cluster I had one Exception related to ClassLoader.
The classes are really simple:
BootFlinkApplication
#SpringBootApplication
#ComponentScan("com.example.demo")
public class BootFlinkApplication {
public static void main(String[] args) {
System.out.println("some test");
SpringApplication.run(BootFlinkApplication.class, args);
}
}
FlinkTest
#Service
public class FlinkTest {
#PostConstruct
public void init() {
StreamExecutionEnvironment see = StreamExecutionEnvironment.getExecutionEnvironment();
see.fromElements(1, 2, 3, 4)
.filter(new RemoveNumber3Filter()).print();
try {
see.execute();
} catch (Exception e) {
System.out.println("Error executing flink job: " + e.getMessage());
}
}
}
RemoveNumber3Filter
public class RemoveNumber3Filter implements FilterFunction<Integer> {
#Override
public boolean filter(Integer i) throws Exception {
return i != 3;
}
}
Exception:
Caused by: org.apache.flink.runtime.client.JobExecutionException: Job execution failed.
at org.apache.flink.runtime.jobmanager.JobManager$$anonfun$handleMessage$1$$anonfun$applyOrElse$6.apply$mcV$sp(JobManager.scala:897)
at org.apache.flink.runtime.jobmanager.JobManager$$anonfun$handleMessage$1$$anonfun$applyOrElse$6.apply(JobManager.scala:840)
at org.apache.flink.runtime.jobmanager.JobManager$$anonfun$handleMessage$1$$anonfun$applyOrElse$6.apply(JobManager.scala:840)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24)
at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:39)
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:415)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
Caused by: org.apache.flink.streaming.runtime.tasks.StreamTaskException: Cannot load user class: com.example.demo.RemoveNumber3Filter
ClassLoader info: URL ClassLoader:
file: '/tmp/blobStore-850f3189-807e-4f8d-a8a6-3bd3c1bd76b4/job_eb93b239080b4d4e09f10f1e3605744d/blob_p-5fd56f3348976c0d333d680fde4a79573c21cd40-48ac0995eee11f38ce3ff4f890102af8' (valid JAR)
Class not resolvable through given classloader.
at org.apache.flink.streaming.api.graph.StreamConfig.getStreamOperator(StreamConfig.java:232)
at org.apache.flink.streaming.runtime.tasks.OperatorChain.createChainedOperator(OperatorChain.java:355)
at org.apache.flink.streaming.runtime.tasks.OperatorChain.createOutputCollector(OperatorChain.java:282)
at org.apache.flink.streaming.runtime.tasks.OperatorChain.<init>(OperatorChain.java:126)
at org.apache.flink.streaming.runtime.tasks.StreamTask.invoke(StreamTask.java:231)
at org.apache.flink.runtime.taskmanager.Task.run(Task.java:718)
at java.lang.Thread.run(Thread.java:748)

You probably use the Spring Boot Maven plugin (https://docs.spring.io/spring-boot/docs/current/reference/html/build-tool-plugins-maven-plugin.html) to repackage your Jar to generate an executable jar, however, it uses a custom boot layout which is not supported by Apache Flink's internal class loader. There should be an original jar file next to the one you try to deploy (.jar.original) which you could use for deployment on the Flink cluster.
As an alternative, you can use a different way of generating a Jar with all your dependencies, such as maven-shade (https://maven.apache.org/plugins/maven-shade-plugin/)

Related

How to completely disable Spring Boot Autoconfiguration?

I'm working on an app and I only want to use Spring's DI features. My problem is that I can't manage to disable Spring Boot's autoconfiguration features. I keep getting this exception:
2020-06-26 14:00:03.240 [main] TRACE o.s.b.diagnostics.FailureAnalyzers - Failed to load org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer
java.lang.NoClassDefFoundError: org/springframework/jdbc/CannotGetJdbcConnectionException
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
at java.lang.Class.getConstructor0(Class.java:3075)
at java.lang.Class.getDeclaredConstructor(Class.java:2178)
at org.springframework.boot.diagnostics.FailureAnalyzers.loadFailureAnalyzers(FailureAnalyzers.java:75)
at org.springframework.boot.diagnostics.FailureAnalyzers.<init>(FailureAnalyzers.java:66)
at org.springframework.boot.diagnostics.FailureAnalyzers.<init>(FailureAnalyzers.java:60)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:204)
at org.springframework.boot.SpringApplication.createSpringFactoriesInstances(SpringApplication.java:441)
at org.springframework.boot.SpringApplication.getSpringFactoriesInstances(SpringApplication.java:427)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:312)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
at MyApplication.main(MyApplication.java:19)
I tried not using #SpringBootApplication only #ComponentScan, but it didn't work. I also tried excluding the relevant autoconfiguration classes:
#SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
JdbcTemplateAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,
XADataSourceAutoConfiguration.class})
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication .class, args);
}
}
but this is not working either. How can I get rid of autoconfiguration completely? I didn't find a #DisableAutoConfiguration annotation, yet there is a #EnableAutoConfiguration.
Edit:
My beans are configured in a separate file in the same package as my application class:
#Configuration
public class BeanConfig {
#Bean
public Database database() {
return DatabaseConfig.configureDatabase();
}
#Bean
public UserRepository userRepository() {
return new InMemoryUserRepository(
Collections.singletonList(new UserEntity(
1,
"user",
Arrays.asList(Permission.ADOPT.name(), Permission.EDIT_PROFILE.name()))));
}
#DependsOn("database")
#Bean
public DogRepository dogRepository() {
return new H2DogRepository();
}
#Bean
public AdoptDog adoptDog() {
return new AdoptDog(dogRepository());
}
#Bean
public FindDogs findDogs() {
return new FindDogs(dogRepository());
}
#Bean
public CreateDog createDog() {
return new CreateDog(dogRepository());
}
#Bean
public DeleteDogs deleteDogs() {
return new DeleteDogs(dogRepository());
}
#Bean
public FindUser findUser() {
return new FindUser(userRepository());
}
#PostConstruct
public void initialize() {
ApplicationEngine engine = ServerConfig.configureServer(
userRepository(), adoptDog(), findDogs(), createDog(), findUser(), deleteDogs());
DogUtils.loadDogs().forEach(dogRepository()::create);
CheckerUtils.runChecks(engine, userRepository());
}
}
I have a different server technology, and I'm using this project to demonstrate Kotlin-Java interoperability (all these files are Kotlin files which are referenced here).
The problem was that Spring was looking for classes which I didn't have (I'm not using any of them) but was necessary for it to work.
Once I added "org.springframework.boot:spring-boot-starter-data-jdbc" and "javax.validation:validation-api:2.0.1.Final" as dependencies it started to work.
Add only spring-boot to dependencies (don't use *-starter-*)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
, and use #ComponentScan instead of #SpringBootApplication.
Actually this may be down to spring.factories in some of your jars and authors violating it. (i.e not listing them under the key of EnableAutoConfiguration as per https://docs.spring.io/autorepo/docs/spring-boot/2.0.0.M3/reference/html/boot-features-developing-auto-configuration.html
In this example, an Application Listener will be registered regardless of auto config enabled or not. May be some of the jars in your class path have beans defined in spring factories
https://www.logicbig.com/tutorials/spring-framework/spring-boot/application-listener-via-spring-factories.html

Spring Boot 2.0.2 + Flowable 6.3.1 Process Deployment

I am trying to integrate Spring Boot 2.0.2 with Flowable 6.3.1. and running into a problem where I am unable to deploy a process one-task-process.bpmn20.xml from the resources/processes/ folder. The XML file is not being picked up and the error says:
Caused by: org.flowable.engine.common.api.FlowableIllegalArgumentException: resource 'one-task-process.bpmn20.xml' not found
at org.flowable.engine.impl.repository.DeploymentBuilderImpl.addClasspathResource(DeploymentBuilderImpl.java:80) ~[flowable-engine-6.3.0.jar:6.3.0]
at com.stsi.pss.Application$1.run(Application.java:458) ~[classes/:na]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:797) [spring-boot-2.0.2.RELEASE.jar:2.0.2.RELEASE]
... 10 common frames omitted
My Spring Boot Application Starter file is as follows and it also prints out the class path which does not include the processes folder.
imports...
#Configuration
#ComponentScan
#EnableAutoConfiguration
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public CommandLineRunner init(final RepositoryService repositoryService,
final RuntimeService runtimeService,
final TaskService taskService) {
return new CommandLineRunner() {
#Override
public void run(String... strings) throws Exception {
ClassLoader cl = ClassLoader.getSystemClassLoader();
URL[] urls = ((URLClassLoader)cl).getURLs();
for(URL url: urls){
System.out.println(url.getFile());
}
System.out.println("Number of process definitions : "
+ repositoryService.createProcessDefinitionQuery().count());
System.out.println("Number of tasks : " + taskService.createTaskQuery().count());
runtimeService.startProcessInstanceByKey("oneTaskProcess");
System.out.println("Number of tasks after process start: "
+ taskService.createTaskQuery().count());
}
};
}
}
I would appreciate any help.
I made a mistake in naming the process definition file. I fixed the filename and the system is working as expected.

Adding JNDI to embedded Tomcat server in Grails 3

When running test-app in grails 3.0, or run-app, grails runs its own version of the embedded Tomcat server. I was able to conclude this from the following link: https://roshandawrani.wordpress.com/2011/03/13/grails-tip-configuring-embedded-tomcat-instance-used-in-developmenttest-env/
However, the context.xml and server.xml files are precompiled with the pulled down libraries. When creating a grails app from scratch, I cannot find either of there two files. Same is true for config.groovy, as it is located within an external library.
I am trying to inject JNDI resources, into the container, so that I can invoke them. Something like this:
<Resource name="myDatasourceName" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="root" password="password" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/my_db_name"/>
In the first link, the authors provide a way to do it in a scripts/_Events.groovy directory, but I do not have this either.
UPDATE 1: Non-working code
import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import org.apache.catalina.Context
import org.apache.catalina.startup.Tomcat
import org.apache.tomcat.util.descriptor.web.ContextResource
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory
import org.springframework.context.annotation.Bean
#SpringBootApplication
class Application extends GrailsAutoConfiguration {
static void main(String[] args) {
GrailsApp.run(Application, args)
}
#Bean
public TomcatEmbeddedServletContainerFactory tomcatFactory() {
return new TomcatEmbeddedServletContainerFactory() {
#Override
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
Tomcat tomcat) {
tomcat.enableNaming();
return super.getTomcatEmbeddedServletContainer(tomcat);
}
#Override
protected void postProcessContext(Context context) {
context.getNamingResources().addResource(preconfigureDbResource("oneSource", "127.0.0.1"))
context.getNamingResources().addResource(preconfigureDbResource("nextSource", "127.0.0.1"))
}
}
}
private ContextResource preconfigureDbResource(String name, String ip) {
ContextResource resource = new ContextResource()
resource.setType("javax.sql.DataSource")
resource.setName("jdbc/" + name)
resource.setProperty("url", "jdbc:oracle:thin:#" + ip + ":1521:ucop")
resource.setProperty("driverClassName", "oracle.jdbc.driver.OracleDriver")
resource.setProperty("username", "coolio")
resource.setProperty("password", "password")
resource.setProperty("auth", "Container")
resource.setProperty("maxTotal", "100")
resource.setProperty("maxIdle", "30")
resource.setProperty("maxWaitMillis", "10000")
return resource;
}
}
I am calling this source like this in my service file:
public DataSource getOneSource() {
Context context = (Context) new InitialContext().lookup("java:/comp/env")
oneSource= (DataSource) context.lookup("jdbc/oneSource")
return oneSource
}
But I am getting an error stating:
javax.naming.NameNotFoundException: Name [comp/env] is not bound in this Context. Unable to find [comp].
Has anyone done this before? I would not be surprised if there is an extra thread that is overwriting the context.
In Grails 3, you do it like this: SampleTomcatJndiApplication
Typically, in Grails web applications, this is in /grails-app/init/Application.groovy
(In my case, I commented out the jndiDataSource() part and just used postProcessContext().)
Source: Graeme Rocher
The solution to this issue is addressed in two steps. First, I had to use the child approach to setting the right context, found in this question. Setting the right context in embedded Tomcat
As imagined, The only change I then had to make was to the getTomcatEmbeddedServletContainer method. I have edited the original to look like this:
#Override
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) {
tomcat.enableNaming();
TomcatEmbeddedServletContainer container =
super.getTomcatEmbeddedServletContainer(tomcat);
for (Container child: container.getTomcat().getHost().findChildren()) {
if (child instanceof Context) {
ClassLoader contextClassLoader =((Context)child).getLoader().getClassLoader();
Thread.currentThread().setContextClassLoader(contextClassLoader);
break;
}
}
return container;
}
Next, I had to edit the gradle build file, to include the dbcp BasicDataSource Dependency. My gradle build file now contains:
dependencies {
// Embedded tomcat dependencies
compile "org.apache.tomcat:tomcat-dbcp:9.0.0.M1"
}

Tomcat 8, Spring Boot, #Configurable LoadTimeWeaving without -javaagent?

I'm trying to setup a #Configurable domain object(not managed by the spring container).
I've got this working by adding the -javaagent:path/to/spring-instrument.jar as a JVM argument but it's not 100% clear to me whether or not this -javaagent MUST be in place. I'm running this on Tomcat 8. I may be misinterpreting the documentation but it seems I may be able to use a another mechanism to accomplish this, in particular this line:
Do not define TomcatInstrumentableClassLoader anymore on Tomcat 8.0 and higher. Instead, let Spring automatically use Tomcat’s new native InstrumentableClassLoader facility through the TomcatLoadTimeWeaver strategy.
Code Samples below:
#SpringBootApplication
#EnableLoadTimeWeaving
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
#Bean
public MyService myService(){
return new MyService();
}
}
#Configurable
public class MyDomainObject {
#Autowired
private MyService myService;
public MyService getMyService(){
return myService;
}
}
public class MyService {
private static final Logger log = LoggerFactory.getLogger(MyService.class);
public void test(){
log.info("test");
}
}
So is there a way to get these #Configrable objects woven without specifying the -javaagent? I'd be interested in learning if I can accomplish this when deploying as WAR to a Standalone Tomcat 8 server and/or using the embedded Tomcat 8 server when launching as a 'fat' jar.
As it stands deploying to Stand alone Tomcat 8 server doesn't throw an error but the getMyService() method above returns null. Launching as a fat jar throws the following error during startup:
Caused by: java.lang.IllegalStateException: ClassLoader [sun.misc.Launcher$AppClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:org.springframework.instrument.jar
I suppose the real question is how do I Specify a custom LoadTimeWeaver in Tomcat 8? Nothing seems to be automatically happening as the documentation states but again I may be misinterpreting what that means exactly.
you can try this :
#Bean
public InstrumentationLoadTimeWeaver loadTimeWeaver() {
return new InstrumentationLoadTimeWeaver();
}
or
there is a new library that just solves to dynamically setup spring InstrumentationLoadTimeWeaver to enable support for aspects without having to start the JVM with an explicit java agent
<dependency>
<groupId>de.invesdwin</groupId>
<artifactId>invesdwin-instrument</artifactId>
<version>1.0.2</version>
</dependency>
#SpringBootApplication
#EnableLoadTimeWeaving
public class TestApplication{
public static void main(final String[] args) {
DynamicInstrumentationLoader.waitForInitialized(); //dynamically attach java agent to jvm if not already present
DynamicInstrumentationLoader.initLoadTimeWeavingContext(); //weave all classes before they are loaded as beans
SpringApplication.run(TestApplication.class, args); //start application, load some classes
}
}
what about creating your own annotation #MyConfigurable ? so you can do what ever you like when it's methods are called.
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Target(ElementType.CONSTRUCTOR)
#Retention(RetentionPolicy.RUNTIME)
public #interface MyConfigurable
{}

Spring boot on glassfish 3.x

I am trying to deploy a Spring Boot application to Glassfish 3.x but I can't get it to work. If I run the project via mvn spring-boot:run or I deploy the war on a Tomcat 7, it works, but if I deploy it on a Glassfish 3.1.2.2 the deploy fails before it even gets to spring boots initialization.
[#|2014-08-04T11:38:36.668+0200|WARNING|glassfish3.1.2|global|_ThreadID=50;_ThreadName=Thread-2;|Error in annotation processing: java.lang.NoClassDefFoundError: org/springframework/batch/core/configuration/annotation/BatchConfigurer|#]
[#|2014-08-04T11:38:36.677+0200|SEVERE|glassfish3.1.2|global|_ThreadID=50;_ThreadName=Thread-2;|Class [ org/flywaydb/core/Flyway ] not found. Error while loading [ class org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration$FlywayConfiguration ]|#]
[#|2014-08-04T11:38:36.700+0200|SEVERE|glassfish3.1.2|javax.enterprise.system.core.com.sun.enterprise.v3.server|_ThreadID=50;_ThreadName=Thread-2;|Exception while deploying the app [spring]|#]
[#|2014-08-04T11:38:36.700+0200|SEVERE|glassfish3.1.2|javax.enterprise.system.core.com.sun.enterprise.v3.server|_ThreadID=50;_ThreadName=Thread-2;|sun.reflect.annotation.TypeNotPresentExceptionProxy
java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy
at sun.reflect.annotation.AnnotationParser.parseClassArray(AnnotationParser.java:673)
at sun.reflect.annotation.AnnotationParser.parseArray(AnnotationParser.java:480)
at sun.reflect.annotation.AnnotationParser.parseMemberValue(AnnotationParser.java:306)
at sun.reflect.annotation.AnnotationParser.parseAnnotation(AnnotationParser.java:241)
at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:88)
at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:70)
at java.lang.Class.initAnnotationsIfNecessary(Class.java:3217)
at java.lang.Class.getAnnotations(Class.java:3197)
at org.glassfish.apf.impl.AnnotationProcessorImpl.processAnnotations(AnnotationProcessorImpl.java:285)
at org.glassfish.apf.impl.AnnotationProcessorImpl.process(AnnotationProcessorImpl.java:195)
at org.glassfish.apf.impl.AnnotationProcessorImpl.process(AnnotationProcessorImpl.java:134)
at com.sun.enterprise.deployment.archivist.Archivist.processAnnotations(Archivist.java:598)
at com.sun.enterprise.deployment.archivist.Archivist.readAnnotations(Archivist.java:456)
at com.sun.enterprise.deployment.archivist.Archivist.readAnnotations(Archivist.java:429)
at com.sun.enterprise.deployment.archivist.Archivist.readRestDeploymentDescriptors(Archivist.java:405)
at com.sun.enterprise.deployment.archivist.Archivist.readDeploymentDescriptors(Archivist.java:380)
at com.sun.enterprise.deployment.archivist.Archivist.open(Archivist.java:243)
at com.sun.enterprise.deployment.archivist.Archivist.open(Archivist.java:252)
at com.sun.enterprise.deployment.archivist.Archivist.open(Archivist.java:213)
at com.sun.enterprise.deployment.archivist.ApplicationFactory.openArchive(ApplicationFactory.java:165)
at org.glassfish.javaee.core.deployment.DolProvider.load(DolProvider.java:185)
at org.glassfish.javaee.core.deployment.DolProvider.load(DolProvider.java:94)
at com.sun.enterprise.v3.server.ApplicationLifecycle.loadDeployer(ApplicationLifecycle.java:827)
at com.sun.enterprise.v3.server.ApplicationLifecycle.setupContainerInfos(ApplicationLifecycle.java:769)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:368)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:240)
at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:389)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$1.execute(CommandRunnerImpl.java:353)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:363)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1085)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1200(CommandRunnerImpl.java:95)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1291)
at org.glassfish.deployment.autodeploy.AutoOperation.run(AutoOperation.java:145)
at org.glassfish.deployment.autodeploy.AutoDeployer.deploy(AutoDeployer.java:575)
at org.glassfish.deployment.autodeploy.AutoDeployer.deployAll(AutoDeployer.java:461)
at org.glassfish.deployment.autodeploy.AutoDeployer.run(AutoDeployer.java:389)
at org.glassfish.deployment.autodeploy.AutoDeployer.run(AutoDeployer.java:380)
at org.glassfish.deployment.autodeploy.AutoDeployService$1.run(AutoDeployService.java:220)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
Disclaimer: I am using a Controller which extends an AbstractController, because we have this structure in another web application, and the next step is to migrate it to Spring Boot.
My configuration so far:
SampleController.java
#Controller("myController")
public class SampleController extends AbstractController {
#Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
response.getWriter().print("Hello world!");
return null;
}
}
Application.java
#EnableAutoConfiguration
#Configuration
#ComponentScan
public class Application extends SpringBootServletInitializer {
#Autowired
ApplicationContext applicationContext;
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
#Bean
public SimpleUrlHandlerMapping sampleServletMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
SampleController sampleController = (SampleController) applicationContext.getBean("myController");
mapping.setUrlMap(Collections.singletonMap("index", sampleController));
mapping.setOrder(0);
return mapping;
}
}
This is a bug in both Glassfish 3.X and Glassfish 4.X.
Maybe it is caused by Glassfish when it attempts to find out Classes that are refenced by Spring boot conditional annotations.
A simple try/catch in Glassfish code solves this problem. look at the proposition here.
You've hit a limitation in GlassFish 3.x and I don't think it's possible to get this to work.
The problem you're seeing is caused by GlassFish scanning your application for annotations. It does this by loading all of the classes in the application and it's failing as a class that's referenced by one of the annotations isn't on the classpath. Unfortunately, there's no way in GlassFish 3 to configure what it does and does not scan for annotations. I believe that things have improved in GlassFish 4 so, if upgrading is an option, you might want to try that.

Resources