Functional Bean Registration returns no bean of type FunctionCatalog on AWS Lambda - spring

I have tried to use the functional bean registration as mentioned in https://spring.io/blog/2018/10/22/functional-bean-registrations-in-spring-cloud-function and to deploy it to AWS Lambda. The traditional way works just fine, see code in https://github.com/mydeveloperplanet/MySpringCloudFunctionPlanet/tree/feature/aws-funtion-bean-definition
However, when I convert the application to the function bean style, the following error occurs:
2020-10-24 11:11:42.910 INFO 8 --- [ main] lambdainternal.AWSLambda : Starting AWSLambda on 169.254.55.181 with PID 8 (/var/runtime/lib/aws-lambda-java-runtime-0.2.0.jar started by sbx_user1051 in /var/task)
2020-10-24 11:11:42.932 INFO 8 --- [ main] lambdainternal.AWSLambda : No active profile set, falling back to default profiles: default
2020-10-24 11:11:44.813 INFO 8 --- [ main] lambdainternal.AWSLambda : Started AWSLambda in 4.559 seconds (JVM running for 6.581)
No qualifying bean of type 'org.springframework.cloud.function.context.FunctionCatalog' available: org.springframework.beans.factory.NoSuchBeanDefinitionException
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.cloud.function.context.FunctionCatalog' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:351)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1127)
at org.springframework.cloud.function.adapter.aws.FunctionInvoker.start(FunctionInvoker.java:124)
at org.springframework.cloud.function.adapter.aws.FunctionInvoker.<init>(FunctionInvoker.java:77)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.base/java.lang.reflect.Constructor.newInstance(Unknown Source)
END RequestId: 1e5c5105-1be5-4388-81f7-f60c77377036
REPORT RequestId: 1e5c5105-1be5-4388-81f7-f60c77377036 Duration: 6842.67 ms Billed Duration: 6900 ms Memory Size: 512 MB Max Memory Used: 47 MB
Unknown application error occurred
org.springframework.beans.factory.NoSuchBeanDefinitionException
The code is the following (and available at GitHub https://github.com/mydeveloperplanet/MySpringCloudFunctionPlanet/tree/master):
#SpringBootConfiguration
public class MySpringCloudFunctionPlanetApplication implements ApplicationContextInitializer<GenericApplicationContext> {
public static void main(String[] args) {
FunctionalSpringApplication.run(MySpringCloudFunctionPlanetApplication.class, args);
}
public Function<String, Boolean> containsCloud() {
return value -> value.contains("cloud");
}
#Override
public void initialize(GenericApplicationContext context) {
context.registerBean("containsCloud", FunctionRegistration.class,
() -> new FunctionRegistration<>(containsCloud())
.type(FunctionType.from(String.class).to(Boolean.class)));
}
}
What am I missing here?

Well, after going down this rabbit hole I finally figured out that, for me, this was because Spring wasn't finding beans like the ContextFunctionCatalogAutoConfiguration. The reason for this in my case is that I was not inheriting from the spring-boot-starter-parent POM and there is critical configuration in there for the Maven Shade plugin to work. The Shade plugin needs to be configured to merge the spring.handlers and spring.schemas files so that Spring can discover these beans which auto register the FunctionCatalog, Jackson ObjectMapper, etc.
So to fix, you can use a configuration like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>aws</shadedClassifierName>
</configuration>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.4.1</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<transformer implementation="org.springframework.boot.maven.PropertiesMergingResourceTransformer">
<resource>META-INF/spring.factories</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>${start-class}</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>

Related

SpringBoot Lambda deployment Issue - EmbeddedServletContainer - java.lang.NoClassDefFoundError

I am trying to deploy a simple springboot app in AWS Lambda/API-Gateway using RequestStreamHandler, but am keep getting the below error.
after looking at internet found that its due to spring-boot package issue so included shade plugin but still no luck.
{
"errorMessage": "Error loading class com.aws.lambda.testlambda.StreamLambdaHandler: org/springframework/boot/context/embedded/EmbeddedServletContainer",
"errorType": "java.lang.NoClassDefFoundError"
}
pom.xml
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.amazonaws.serverless</groupId>
<artifactId>aws-serverless-java-container-spring</artifactId>
<version>1.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<transformer
implementation="org.springframework.boot.maven.PropertiesMergingResourceTransformer">
<resource>META-INF/spring.factories</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.aws.lambda.testlambda.TestlambdaApplication</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
public class StreamLambdaHandler implements RequestStreamHandler {
private static SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
static {
try {
handler = SpringBootLambdaContainerHandler.getAwsProxyHandler(TestlambdaApplication.class);
// we use the onStartup method of the handler to register our custom filter
handler.onStartup(servletContext -> {
FilterRegistration.Dynamic registration = servletContext.addFilter("CognitoIdentityFilter", CognitoIdentityFilter.class);
registration.addMappingForUrlPatterns( EnumSet.of( DispatcherType.REQUEST), true, "/*");
});
} catch (ContainerInitializationException e) {
// if we fail here. We re-throw the exception to force another cold start
e.printStackTrace();
throw new RuntimeException("Could not initialize Spring Boot application", e);
}
}
public StreamLambdaHandler() {
// we enable the timer for debugging. This SHOULD NOT be enabled in production.
Timer.enable();
}
#Override
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
throws IOException {
handler.proxyStream(inputStream, outputStream, context);
// just in case it wasn't closed by the mapper
outputStream.close();
}
}
Any help is much appreciated. Thanks in advance.
I was able to fix this issue, there are couple of issues to fix and make it work end to end.
Referred below url for this issue.
https://github.com/awslabs/aws-serverless-java-container
Packaging needs to exclude tomcat dependency.
RequestStreamHandler needs to be modified little to process the request and response.
AwsProxyResponse resp = handler.proxy(req, context);
LambdaContainerHandler.getObjectMapper().writeValue(outputStream, resp);
Had to choose Proxy Integration option while deploying to API Gateway.
AVAI!
I have a guess on this problem.
Could you check the version of Java that is defined on your Lambda function?
I see you are using Java 8 your application.
Your lambda runtime should match this version.
You may also face some issues if you are using locally Oracle JVM and AWS Coretto JVM on your lambda.

Cucumber Parallel Testing giving weird results

I'm trying to run my cucumber project (two runner classes) in parallel browsers and I am getting weird results. When I do a mvn verify, first it will run each runner class sequentially. The first will pass and the second will fail due to the following error -
org.openqa.selenium.NoSuchSessionException: Session ID is null. Using WebDriver after calling quit()?
Then right after, it will run both runner classes in parallel (like I want it to), and all will pass just fine. And maven will report the Build Success.
I am not initializing the webdriver in the #Before annotation. Instead I am using cucumber-picocontainer dependency injection right into my step definition classes. I have tried swapping driver.close() and driver.quit() in my #After annotation, but that didn't change the results. Please find some code snippets below and then my POM. Many thanks in advance.
public class GivenSteps {
WebDriver driver;
CustomWaits waits;
public GivenSteps(DependencyInjection dependencyInjection) {
this.driver = dependencyInjection.getDriver();
this.waits = dependencyInjection.getWaits();
}
Hooks -
public class Hooks {
WebDriver driver;
public Hooks(DependencyInjection dependencyInjection) {
this.driver = dependencyInjection.getDriver();
}
#Before("#setup")
public void setUp() {
driver.manage().deleteAllCookies();
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
driver.manage().timeouts().pageLoadTimeout(20, TimeUnit.SECONDS);
}
#After("#destroy")
public void tearDown() throws Throwable {
//driver.close();
driver.quit();
}
Dependency Injection -
public class DependencyInjection {
private static String browserType = Settings.BROWSER.getValue();
private static WebDriver driver = null;
private static CustomWaits waits = null;
public WebDriver getDriver() {
if (driver == null) {
driver = utilities.DriverFactory.createDriver(browserType);
}
return driver;
}
POM.xml -
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
<configuration>
<testFailureIgnore>true</testFailureIgnore>
<includes>
<exclude>
**/*Runner.java
</exclude>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>com.github.temyers</groupId>
<artifactId>cucumber-jvm-parallel-plugin</artifactId>
<version>5.0.0</version>
<executions>
<execution>
<id>generateRunners</id>
<phase>generate-test-sources</phase>
<goals>
<goal>generateRunners</goal>
</goals>
<configuration>
<glue>
<package>test.java.stepDefinitions</package>
</glue>
<outputDirectory>target/generated-test-sources/cucumber</outputDirectory>
<featuresDirectory>src/test/resource/</featuresDirectory>
<cucumberOutputDir>target/Reports/</cucumberOutputDir>
<namingPattern>Runner{c}</namingPattern>
<!-- One of [SCENARIO, FEATURE]. SCENARIO generates one runner per
scenario. FEATURE generates a runner per feature. -->
<parallelScheme>FEATURE</parallelScheme>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.19.1</version>
<executions>
<execution>
<id>acceptance-test</id>
<phase>integration-test</phase>
<goals>
<goal>integration-test</goal>
</goals>
<configuration>
<forkCount>10</forkCount>
<reuseForks>true</reuseForks>
<includes>
<include>**/*Runner.class</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
I had to comment out the section in my POM.xml -> maven-surefire-plugin because now I am only using maven-failsafe-plugin
Originally I had both active in my POM, so both were running sequentially.

Spring Integration application does not define channels when executed as packaged jar

I started to use Spring Integration in a project at work. Everything was looking fine and running smoothly on my local dev environment (when executed from Eclipse).
However, when I tried to deploy to our dev/staging environment I got some issues related with the definition of the Spring Integration channels.
After a couple of hours completely clueless (blaming external dependencies, our development/staging environment setup etc etc), I came to realize that I would get exactly the same issue whenever I tried to execute my application as a packaged jar (on my local machine)
I did a small "sample" application without any other dependencies in order to reproduce this issue. Once again everything works fine from eclipse but whenever executed as a packaged jar the following exception was thrown:
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'gatewayChannel' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:687)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1207)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.integration.support.channel.BeanFactoryChannelResolver.resolveDestination(BeanFactoryChannelResolver.java:89)
at org.springframework.integration.support.channel.BeanFactoryChannelResolver.resolveDestination(BeanFactoryChannelResolver.java:46)
at org.springframework.integration.gateway.MessagingGatewaySupport.getRequestChannel(MessagingGatewaySupport.java:344)
at org.springframework.integration.gateway.MessagingGatewaySupport.send(MessagingGatewaySupport.java:385)
at org.springframework.integration.gateway.GatewayProxyFactoryBean.invokeGatewayMethod(GatewayProxyFactoryBean.java:481)
at org.springframework.integration.gateway.GatewayProxyFactoryBean.doInvoke(GatewayProxyFactoryBean.java:433)
at org.springframework.integration.gateway.GatewayProxyFactoryBean.invoke(GatewayProxyFactoryBean.java:424)
at org.springframework.integration.gateway.GatewayCompletableFutureProxyFactoryBean.invoke(GatewayCompletableFutureProxyFactoryBean.java:65)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy24.send(Unknown Source)
at com.test.App$RealApp.doThings(App.java:52)
at com.test.App.main(App.java:62)
Bellow you can find the code of my sample application and the pom that I used to build my packaged jar.
#ComponentScan
#EnableIntegration
#IntegrationComponentScan
#Configuration
public class App {
#MessagingGateway
public interface GatewayApp {
#Gateway(requestChannel = "gatewayChannel")
void send(String string);
}
#Bean
public IntegrationFlow inboud() {
return IntegrationFlows.from("gatewayChannel")
.handle(System.out::println)
.get();
}
#Component
public class RealApp {
#Autowired
private GatewayApp gateway;
public void doThings() {
gateway.send("yeee");
}
}
#SuppressWarnings("resource")
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(App.class);
context.refresh();
context.getBean(RealApp.class).doThings();
}
}
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>sprint-integration</groupId>
<artifactId>integration</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>integration</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.3.14.RELEASE</spring.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<configuration>
<createDependencyReducedPom>true</createDependencyReducedPom>
<createSourcesJar>false</createSourcesJar>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>yo-service</finalName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Spring Integration -->
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-amqp</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-java-dsl</artifactId>
<version>1.2.3.RELEASE</version>
</dependency>
</dependencies>
</project>
Note: I think this issue might have exaclty the same cause as the one reported in Spring integration bootstrap - intellij in debug works, packaged jar does not
My best guess is the shade plugin is having some effect on the order in which BeanPostProcessors are run.
Does the app work if you explicitly define the channel...
#Bean
public MessageChannel gatewayChannel() {
return new DirectChannel();
}
...?
If so, that would be a smoking gun. In that case, the next step would be to get a DEBUG log for org.springframework in both environments and compare the bean definition/creation/post processing logs.
If you can post a complete (simple) example that exhibits the problem, we can take a look.
EDIT
The problem is the shade plugin does not merge the META-INF/spring.factories files, so we lose the entry from the JAVA DSL and hence don't process any IntegrationFlows...
From the Uber jar we just have the core file...
org.springframework.integration.config.IntegrationConfigurationInitializer=\
org.springframework.integration.config.GlobalChannelInterceptorInitializer,\
org.springframework.integration.config.IntegrationConverterInitializer,\
org.springframework.integration.config.IdempotentReceiverAutoProxyCreatorInitializer
and so are missing the additional initializer from the DSL jar...
org.springframework.integration.config.IntegrationConfigurationInitializer=\
org.springframework.integration.dsl.config.DslIntegrationConfigurationInitializer
Hence it works with 5.0.1 because the DSL is now part of core.
Spring Boot solves this problem by nesting the jars instead of extracting all the classes.
EDIT2
Here's another work-around, if you can't move to Spring Integration 5. Add this bean to your application...
#Bean
public static BeanFactoryPostProcessor dslInitializer() {
return new BeanFactoryPostProcessor() {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) throws BeansException {
new DslIntegrationConfigurationInitializer().initialize(bf);
}
};
}
(Notice static).
Adding to Gary Russell's answer: The problem is indeed that the META-INF/spring.factories files are not automatically merged by the shade plugin.
You can use the AppendingTransformer of the shade plugin to merge these files.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.my.MainClass</mainClass>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.tooling</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.factories</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>

ProGuard + Spring Boot + Maven Plugin

Guys, I'm trying to obfuscate a .jar application using the proguard-maven-plugin.
When I try to perform the obfuscate process, I get error messages stating that there are unexpected classes.
I'm using the Spring Boot 1.4.1.RELEASE and Proguard Maven Plugin 2.0.13.
This is my proguard.conf
-injars /workspace/base/target/test-1.0.0.jar
-libraryjars /Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/rt.jar
-dontshrink
-dontoptimize
-dontobfuscate
-dontusemixedcaseclassnames
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,LocalVariable*Table,*Annotation*,Synthetic,EnclosingMethod
-adaptresourcefilenames **.properties
-adaptresourcefilecontents **.properties,META-INF/MANIFEST.MF
-dontpreverify
-verbose
-keepclasseswithmembers public class * {
public static void main(java.lang.String[]);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * extends java.beans.BeanInfo
-keep class * {
void set*(***);
void set*(int,***);
boolean is*();
boolean is*(int);
*** get*();
*** get*(int);
}
-assumenosideeffects public class java.lang.System {
public static long currentTimeMillis();
static java.lang.Class getCallerClass();
public static int identityHashCode(java.lang.Object);
public static java.lang.SecurityManager getSecurityManager();
public static java.util.Properties getProperties();
public static java.lang.String getProperty(java.lang.String);
public static java.lang.String getenv(java.lang.String);
public static java.lang.String mapLibraryName(java.lang.String);
public static java.lang.String getProperty(java.lang.String,java.lang.String);
}
The pom.xml file. I am only informing the configuration by the plugin.
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<version>2.0.13</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
<obfuscate>false</obfuscate>
<outFilter>**/BOOT-INF/classes/ **.class</outFilter>
<proguardInclude>${basedir}/proguard.conf</proguardInclude>
<outputDirectory>${project.build.directory}</outputDirectory>
<injar>${project.build.finalName}.jar</injar>
<outjar>${project.build.finalName}-min.jar</outjar>
</configuration>
</plugin>
However, during the execution process I get the following return for all classes in my application.
Warning: class [BOOT-INF/classes/br/com/base/BaseApplication.class] unexpectedly contains class [br.com.base.BaseApplication]
Warning: class [BOOT-INF/classes/br/com/base/controller/CaixaController.class] unexpectedly contains class [br.com.base.controller.CaixaController]
[...]
And the final output of ProGuard. PS: All classes are in the BOOT-INF/classes directory
Warning: there were 97 classes in incorrectly named files.
You should make sure all file names correspond to their class names.
The directory hierarchies must correspond to the package hierarchies.
(http://proguard.sourceforge.net/manual/troubleshooting.html#unexpectedclass)
If you don't mind the mentioned classes not being written out,
you could try your luck using the '-ignorewarnings' option.
Please correct the above warnings first.
Can anyone imagine any alternatives I can try?
Thanks.
In order to fix this, I made sure to change the order of the plugins in the pom. The proguard plugin should go first, followed by the spring boot plugin.
Additionally, make sure you have the <goal>repackage</goal> specified in the spring boot configuration. With the correct order and the repackage goal specified, the proguard obfuscation/optimization/whatever you have configured will take place and produce a jar. Then the spring boot plugin will repackage that jar as an executable and everything should work.
My plugin configuration from pom.xml:
<project ...>
....
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
<proguardInclude>${basedir}/proguard.conf</proguardInclude>
<libs>
<lib>${java.home}/lib/rt.jar</lib>
<lib>${java.home}/lib/jce.jar</lib>
</libs>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<start-class>org.springframework.boot.loader.JarLauncher</start-class>
</configuration>
</execution>
</executions>
</plugin>
...

Failsafe integration tests running on jetty-maven-plugin hanging or/and OutOfMemoryError

When running maven failsafe plugin with jetty maven plugin with the following configuration
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>8.1.15.v20140411</version>
<configuration>
<stopKey>STOP</stopKey>
<stopPort>9999</stopPort>
<scanIntervalSeconds>5</scanIntervalSeconds>
<webAppConfig>
<contextPath>/${project.artifactId}</contextPath>
</webAppConfig>
<connectors>
<connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
<port>8181</port>
</connector>
</connectors>
<contextXml>${project.build.testOutputDirectory}/jetty-context.xml</contextXml>
</configuration>
<executions>
<execution>
<id>start-jetty</id>
<phase>pre-integration-test</phase>
<goals>
<goal>run-war</goal>
</goals>
<configuration>
<scanIntervalSeconds>0</scanIntervalSeconds>
<daemon>true</daemon>
</configuration>
</execution>
<execution>
<id>stop-jetty</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.17</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<versionenter code here>2.17</version>
</dependency>
</dependencies>
<configuration>
<includes>
<include>**/*IntegrationTest.java</include>
</includes>
<additionalClasspathElements>
<additionalClasspathElement>${documentum.home}</additionalClasspathElement>
</additionalClasspathElements>
<argLine>-Xmx1024m -XX:MaxPermSize=2048m</argLine>
</configuration>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
Maven hangs on the following lines:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.fee.services.dctmsp.test.FooSpRepositoryServiceTest
Getting session manager... OK - took 4932 ms
Getting session... OK - took 1085 ms
serviceFactory: com.emc.documentum.fs.rt.context.ServiceFactory#2743724e
spRepositoryService: JAX-WS RI 2.1.7-b01-: Stub for http://localhost:8181/fooSP/services/fooSP/FooSpRepositoryService
Sometimes i get this:
com.sun.xml.ws.transport.http.servlet.WSServletDelegate doGet
SEVERE: caught throwable
java.lang.OutOfMemoryError: PermGen space
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:421)
at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:383)
at com.emc.documentum.fs.rt.DfsException.<init>(DfsException.java:91)
at com.emc.documentum.fs.rt.DfsException.<init>(DfsException.java:73)
at com.emc.documentum.fs.rt.ServiceException.<init>(ServiceException.java:56)
at com.emc.documentum.fs.rt.ServiceInvocationException.<init>(ServiceInvocationException.java:36)
at com.emc.documentum.fs.rt.AuthenticationException.<init>(AuthenticationException.java:35)
at com.emc.documentum.fs.rt.impl.handler.AuthorizationHandler.authenticate(AuthorizationHandler.java:130)
at com.emc.documentum.fs.rt.impl.handler.AuthorizationHandler.handleMessage(AuthorizationHandler.java:55)
at com.emc.documentum.fs.rt.impl.handler.AuthorizationHandler.handleMessage(AuthorizationHandler.java:1)
at com.sun.xml.ws.handler.HandlerProcessor.callHandleMessage(HandlerProcessor.java:284)
at com.sun.xml.ws.handler.HandlerProcessor.callHandlersRequest(HandlerProcessor.java:135)
at com.sun.xml.ws.handler.ServerSOAPHandlerTube.callHandlersOnRequest(ServerSOAPHandlerTube.java:134)
at com.sun.xml.ws.handler.HandlerTube.processRequest(HandlerTube.java:116)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:598)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:557)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:542)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:439)
at com.sun.xml.ws.server.WSEndpointImpl$2.process(WSEndpointImpl.java:243)
at com.sun.xml.ws.transport.http.HttpAdapter$HttpToolkit.handle(HttpAdapter.java:471)
at com.sun.xml.ws.transport.http.HttpAdapter.handle(HttpAdapter.java:244)
at com.sun.xml.ws.transport.http.servlet.ServletAdapter.handle(ServletAdapter.java:135)
at com.sun.xml.ws.transport.http.servlet.WSServletDelegate.doGet(WSServletDelegate.java:129)
And some other times I get this:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.foo.services.dctmsp.test.FooSpRepositoryServiceTest
Getting session manager... OK - took 5914 ms
Getting session... OK - took 1072 ms
serviceFactory: com.emc.documentum.fs.rt.context.ServiceFactory#111edceb
spRepositoryService: JAX-WS RI 2.1.7-b01-: Stub for http://localhost:8181/fooSP/services/fooSP/FooSpRepositoryService
2014-09-18 14:32:50.353:WARN:oejs.ServletHandler:Error for /fooSP/services/fooSP/FooSpRepositoryService
java.lang.OutOfMemoryError: PermGen space
2014-09-18 14:32:51.871:WARN:oejs.ServletHandler:Error for /fooSP/services/fooSP/FooSpRepositoryService
java.lang.OutOfMemoryError: PermGen space
Exception in thread "Thread-14" java.lang.OutOfMemoryError: PermGen space
Exception in thread "Thread-15" java.lang.OutOfMemoryError: PermGen space
Now, I have tried with different settings for MaxPermSize, but it doesn't seem to help, everything ranging from 64M to 5000M.
Here is the test code that I am running:
#Category(IntegrationTest.class)
public class FooSpRepositoryServiceTest extends FooSpCommon {
IFooSpRepositoryService spRepositoryService = null;
ArrayList<ISbDokument> dokumenter = new ArrayList<ISbDokument>();
ServiceFactory serviceFactory = null;
#Before
public void setUp() {
super.setUp();
try {
serviceFactory = ServiceFactory.getInstance();
spRepositoryService = serviceFactory.getRemoteService(IFooSpRepositoryService.class, serviceContext,
FOO_SERVICE_MODULE, FOO_SP_HOST);
System.out.println("serviceFactory: " + serviceFactory);
System.out.println("spRepositoryService: " + spRepositoryService);
} catch (Exception e) {
e.printStackTrace();
}
}
#After
public void tearDown() {
try {
if (dokumenter.size() > 0) {
for (ISbDokument dokument : dokumenter) {
if (dokument.isCheckedOut())
dokument.checkin(true, "CURRENT");
dokument.destroyAllVersions();
}
}
} catch (Exception e) {
e.printStackTrace();
}
if (session != null) {
sessionMgr.release(session);
}
}
#Test
public void test_dummy() {
String dummystring = "hello";
assertEquals(dummystring, "hello");
}
#Test
public void test_dummy1() {
assertTrue(serviceFactory != null);
assertTrue(spRepositoryService != null);
}
#Test
public void test_getFormatName_Text() throws ServiceException {
String formatName = spRepositoryService.getFormatName(REPOSITORY, "txt");
assertTrue(formatName != null);
assertTrue(!formatName.equalsIgnoreCase(""));
assertEquals(formatName, "crtext");
}
}
The problem apparently occurs in the method test_getFormatName_Text when spRepositoryService.getFormatName is invoked, because the other tests don't fail. What happens whenever I don't get any "java.lang.OutOfMemoryError: PermGen space" is that it hangs forever.

Resources