Thursday, May 13, 2021

AWS Java Lambda package ways

 There is two ways to make Aws Java Lambda packages, one is to make a uber FAT jar with the shade plugin.


Many people are in two camps on this, as well as it causing major problems with duplicates and needing custom code to make things 'happy'.


An example of this is below


<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="com.github.edwgiz.maven_shade_plugin.log4j2_cache_transformer.PluginsCacheFileTransformer">
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>

The second way is to make a zip, it like a .war file in a way and still works, there is more maven configuration of setting up. This also allows a split to occur with the use of Lambda Layers (playing the lib's as a layer) 

<!-- alternative way without needing to use shader -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<finalName>${project.build.finalName}</finalName>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.2</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeScope>runtime</includeScope>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/main/assembly/bin.xml</descriptor>
</descriptors>
<attach>false</attach>
</configuration>
</execution>
</executions>
</plugin>
<!-- END alternative way without needing to use shader -->

This does require an assembly xml file placed at  src/main/assembly/bin.xml
<assembly>
<id>aws-lambda-package</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.build.directory}${file.separator}lib</directory>
<outputDirectory>lib</outputDirectory>
<useDefaultExcludes>true</useDefaultExcludes>
</fileSet>
<!-- copy all classes -->
<fileSet>
<directory>${project.build.directory}${file.separator}classes</directory>
<includes>
<include>**</include>
</includes>
<outputDirectory>${file.separator}</outputDirectory>
</fileSet>
</fileSets>
</assembly> 

Upload the zip instead of jar. All is good.

See https://github.com/awslabs/aws-serverless-java-container/commit/22edc6e65dcdefab46145f80c80dcb274b0eedd4 

Tuesday, May 04, 2021

Junit 4 to Junit 5 upgrade

 So you started to upgrade from old junit 4 to the new junit 5 api spec.


Sadly the move the packages around. Its best to follow other docs out on the web for this like 

https://www.baeldung.com/junit-filtering-tests


Now heres a gotcha, if you are upgrading your springboot tests from junit4 to junit 5 and are trying to use tags to drop external tests or slow tests and it is not working. 


It might actually be the import Test class that is breaking it.

Replace import org.junit.Test; with import org.junit.jupiter.api.Test;

This should make everything work correctly again.


Then the command below can work.

mvn test  -DexcludedGroups=ExternalIntegrationTest 


Tuesday, April 20, 2021

Major change between spring-boot 2.2.x to 2.4.x with spring-cloud and spring-cloud-starter-aws-parameter-store-config (bootstrap.yml, profiles and more)

So with the change in how versioning works. A change to how config is loaded by default and a split between cloud agnostic spring-cloud and vendor specific integration types. There has been a major shake up on how to upgrade to the next minor version of spring-boot.


<parent>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-parent</artifactId>

-        <version>2.2.11.RELEASE</version>

+        <version>2.4.4</version>

        <relativePath></relativePath><!--empty to not look up parent folder which is a helper pom on building-->

</parent>


-<spring-cloud.version>Hoxton.SR5</spring-cloud.version> <!-- https://spring.io/projects/spring-cloud release trains, Greenwich 2.1.x, Haxton 2.2.x -->

+<spring-cloud.version>2020.0.2</spring-cloud.version> <!-- https://spring.io/projects/spring-cloud release trains, Greenwich 2.1.x, Haxton 2.2.x, 2020.0.2 2.4.x -->


We now need to include io.awspring.cloud:spring-cloud-aws-dependencies as its now not included in the upstream org.springframework.cloud:spring-cloud-dependencies

    <dependencyManagement>

        <dependencies>

            <!-- spring cloud and aws cloud for param store lookup -->

            <dependency><scope>import</scope><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type></dependency>

+            <dependency><scope>import</scope><groupId>io.awspring.cloud</groupId><artifactId>spring-cloud-aws-dependencies</artifactId><version>2.3.1</version><type>pom</type></dependency>

..

          

          

With dependencies we don't include spring-cloud-starter any more but with bootstrap.yml not being the 'default' way for loading we now need to include spring-cloud-starter-bootstrap to re-enable that functionality

-        <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter</artifactId></dependency>

-        <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-aws-parameter-store-config</artifactId></dependency>


+        <!-- spring-cloud-starter-bootstrap required to enable bootstrap.yml due to it not being default anymore -->

+        <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId></dependency>

+        <!-- aws parm store config changed home-->

+        <dependency><groupId>io.awspring.cloud</groupId><artifactId>spring-cloud-starter-aws-parameter-store-config</artifactId></dependency>

          

          

You now can't have spring profiles load other profiles, you can do profile groups, but that is limited if you wanted something dynamic like enabling proxy settings. (this is maven profile adding a spring profile)

<profile>

        <id>local-proxy</id>

        <activation>

            <property>

                <name>env.http_proxy</name>

            </property>

        </activation>

        <properties>

-                <springBootRunArguments>--spring.profiles.include=PROXY,</springBootRunArguments>

+                <springBootRunArguments>--spring.config.import=classpath:application-PROXY.yml</springBootRunArguments>

        </properties>

        <build>

            <plugins>

                <plugin>

                    <artifactId>maven-surefire-plugin</artifactId>

                    <version>${maven-surefire-plugin.version}</version>

                    <configuration>

                        <systemPropertyVariables>

-                            <spring.profiles.include>PROXY</spring.profiles.include>

+                            <spring.config.import>classpath:application-PROXY.yml</spring.config.import>

                        </systemPropertyVariables>

                    </configuration>

                </plugin>

                <plugin>

                    <artifactId>maven-failsafe-plugin</artifactId>

                    <configuration>

                        <systemPropertyVariables>

-                            <spring.profiles.include>PROXY</spring.profiles.include>

+                            <spring.config.import>classpath:application-PROXY.yml</spring.config.import>

                        </systemPropertyVariables>

                    </configuration>

                </plugin>

                <plugin>

                    <groupId>org.springframework.boot</groupId>

                    <artifactId>spring-boot-maven-plugin</artifactId>

                    <configuration>

-                        <jvmArguments>-Dspring-boot.run.jvmArguments='-Dspring.profiles.include="PROXY"'</jvmArguments>

+                        <jvmArguments>-Dspring-boot.run.jvmArguments='-Dspring.config.import="classpath:application-PROXY.yml"'</jvmArguments>

                    </configuration>

                </plugin>


            </plugins>

        </build>

    </profile>

          

Any properties files you may have loaded that used "spring.profiles.include" can't be used any more with 2.4.x+ (unless you enabled legacy which will be going away after 2.6.x? version i believe)

          

-spring.profiles.include: defaults

+spring.config.import: classpath:application-defaults.yml

          

Also ensure that your bootstrap.yml has

aws.paramstore.enabled: true

It is on by default (But as its nowvin your config you can set it to false for local run's)

          

For more info, see:

https://spring.io/blog/2020/08/14/config-file-processing-in-spring-boot-2-4

https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-external-config-files-profile-specific

https://github.com/awspring/spring-cloud-aws/blob/2.3.x/docs/src/main/asciidoc/parameter-store.adoc

https://github.com/awspring/spring-cloud-aws/blob/2.3.x/spring-cloud-starter-aws-parameter-store-config/src/test/java/io/awspring/cloud/autoconfigure/paramstore/AwsParamStoreBootstrapConfigurationTest.java

https://stackoverflow.com/questions/64907675/including-profiles-in-spring-boot-2-4-0-version

https://stackoverflow.com/questions/64994034/bootstrap-yml-configuration-not-processed-anymore-with-spring-cloud-2020-0

https://stackoverflow.com/questions/65063402/why-bootstrap-properties-is-ignored-by-spring-cloud-starter-config

https://docs.awspring.io/spring-cloud-aws/docs/2.3.0/reference/html/index.html#integrating-your-spring-cloud-application-with-the-aws-parameter-store

          

          

Something I want to look into is setting up something like https://github.com/localstack/localstack within a maven project so that param store loading can be tested in pdev instead of being caught in an aws dev/test environment.