Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add dependency JAR in java azure functions

Is there a way to add third party jars to Azure functions using JAVA. I would need to have the json-simple jar and jackson-databind jars to be available for the function at run time. Right now, My code throws a runtime exception(ClassNotFound Exception) as the function is not able to reference the jar during runtime because it is unavailable.

I tried using maven-shade-plugin. It does create an executable jar including the external jars but the deployment still takes the original jar.

Please suggest.

Thanks.

POM.xml

<?xml version="1.0" encoding="UTF-8"?>
<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>com.sce.api.learning</groupId>
    <artifactId>myApi</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>Azure Java Functions</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <functionAppName>mckapi-http-nov2</functionAppName>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.microsoft.azure</groupId>
            <artifactId>azure-functions-java-core</artifactId>
            <version>1.0.0-beta-1</version>
        </dependency>

        <!-- Adding GSON dependancy -->
        <dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>1.4</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.6.3</version>
</dependency>

<dependency>
    <groupId>com.googlecode.json-simple</groupId>
    <artifactId>json-simple</artifactId>
    <version>1.1.1</version>
</dependency>
<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20171018</version>
</dependency>

        <!-- Test -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <groupId>com.microsoft.azure</groupId>
                    <artifactId>azure-functions-maven-plugin</artifactId>
                    <version>0.1.4</version>
                </plugin>
            </plugins>
        </pluginManagement>

        <plugins>
            <plugin>
                <groupId>com.microsoft.azure</groupId>
                <artifactId>azure-functions-maven-plugin</artifactId>
                <configuration>
                    <resourceGroup>java-functions-group</resourceGroup>
                    <appName>${functionAppName}</appName>
                    <region>westus2</region>
                    <appSettings>
                        <property>
                            <name>FUNCTIONS_EXTENSION_VERSION</name>
                            <value>beta</value>
                        </property>
                    </appSettings>
                </configuration>
                <executions>
                    <execution>
                        <id>package-functions</id>
                        <goals>
                            <goal>package</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-resources</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <overwrite>true</overwrite>
                            <outputDirectory>${project.build.directory}/azure-functions/${functionAppName}
                            </outputDirectory>
                            <resources>
                                <resource>
                                    <directory>${project.basedir}</directory>
                                    <includes>
                                        <include>host.json</include>
                                        <include>local.settings.json</include>
                                        **<include>**/*.jar</include>**<!-- This includes the jar files in the target/lib folder -->
                                    </includes>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                        <overwrite>true</overwrite>
                            <outputDirectory>${project.build.directory}/azure-functions/${functionAppName}
                            </outputDirectory>
              <shadedArtifactAttached>false</shadedArtifactAttached>
            </configuration>
                    </execution>
                </executions>
                <configuration>
                    <finalName>${artifactId}-${version}</finalName>
                </configuration>
            </plugin>

        </plugins>

    </build>

</project>
like image 418
mack Avatar asked Nov 07 '17 22:11

mack


People also ask

Does Azure Functions support Java?

Java function basicsA single package is deployed to a function app in Azure. When running in Azure, the function app provides the deployment, execution, and management context for your individual Java functions.

How do I run Azure function locally in Java?

Run functions locally in the IDE Azure Functions Core Tools, version 2 must be installed to run and debug functions locally. Right-click on the generated project, then choose Run As and Maven build. In the Edit Configuration dialog, Enter package in the Goals, then select Run.


2 Answers

I had the same problem and I figured out how to arrange a solution.

First of all, start from a brand new Maven project following the straightforward guide at this link.

Assume <project_root_path> as the folder where you will create the project.

Once you have generated your maven project, just add this maven-assembly-plugin plugin on your <project_root_path>/pom.xml within <build><plugins>...</plugins></build>:

<plugin>
   <artifactId>maven-assembly-plugin</artifactId>
   <configuration>
      <outputDirectory>${project.build.directory}/azure-functions/${functionAppName}</outputDirectory>
      <appendAssemblyId>false</appendAssemblyId>
      <descriptorRefs>
         <descriptorRef>jar-with-dependencies</descriptorRef>
      </descriptorRefs>
      <archive />
   </configuration>
   <executions>
      <execution>
         <id>make-assembly</id>
         <phase>package</phase>
         <goals>
            <goal>assembly</goal>
         </goals>
      </execution>
   </executions>
</plugin>

Compiling and packaging the Azure Function with command mvn clean compile package will produce a jar on path <project_root_path>/target/<project_name>.jar containing all the external libraries listed under the <dependencies></dependencies> of the pom.xml.

Note 1: if you didn't modify the standard pom.xml, <project_name> will be generated according to <artifactId>_<version>.jar.

Note 2: if you don't use the <appendAssemblyId>false</appendAssemblyId> directive on the above snippet, the <project_name> will be <artifactId>_<version>-<descriptorRef>.jar. Consider this for the following instructions.

So, now you should have your complete <project_root_path>/target/<project_name>.jar, but before using it you have to copy it under <project_root_path>/target/azure-functions/<azure_function_name>/ where <azure_function_name> is the name you gave to your function during the creation progress documented on the above link.

Now you can test it using the Azure Maven plugins:

  1. Running the Azure Function on your machine locally: mvn azure-functions:run
  2. Deploying the Azure Function on your subscription: mvn azure-functions:deploy

At the end, the key point is moving the jar generated with maven-assembly-plugin into the right place where the Azure Maven plugin will look during the run/deploy process. I wish I could find a more automatic way using standard Maven commands.

Hope this helps.

Ciao IP

Edit (17/11/17)

Adding <outputDirectory>${project.build.directory}/azure-functions/${functionAppName}</outputDirectory> within the <configuration> POM tag and changing <goal> tag to assembly, it makes Maven to automatically copy the final JAR in the Azure Function staging directory. This allows the mvn azure-functions:run and mvn azure-functions:deploy commands to directly use the correct JAR file containing all dependency. No manual actions are requested anymore.

The above POM have been updated accordingly.

Edit (21/11/17)

In case you want to use the Maven Shade Plugin instead of the Maven Assembly Plugin, replace the above XML snippet with this one:

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-shade-plugin</artifactId>
   <version>3.1.0</version>
   <configuration>
      <shadedArtifactAttached>false</shadedArtifactAttached>
      <outputFile>${project.build.directory}/azure-functions/${functionAppName}/${project.artifactId}-${project.version}.jar</outputFile>
      <filters>
         <filter>
            <artifact>*:*</artifact>
            <excludes>
               <exclude>META-INF/*.SF</exclude>
               <exclude>META-INF/*.DSA</exclude>
               <exclude>META-INF/*.RSA</exclude>
            </excludes>
         </filter>
      </filters>
   </configuration>
   <executions>
      <execution>
         <phase>package</phase>
         <goals>
            <goal>shade</goal>
         </goals>
      </execution>
   </executions>
</plugin>

It will work using the same standard Maven commands mentioned before.

like image 97
iakko Avatar answered Nov 15 '22 21:11

iakko


The latest version of pom.xml generated by the azure-functions-archetype that you use to prepare the Azure Function project (see this link for more details) seems to already include the plugin to copy dependencies.

My pom.xml includes the following plugin by default, and it seems to copy the dependencies that I have specified into the ${stagingDirectory}/lib automatically.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>${stagingDirectory}/lib</outputDirectory>
                <overWriteReleases>false</overWriteReleases>
                <overWriteSnapshots>false</overWriteSnapshots>
                <overWriteIfNewer>true</overWriteIfNewer>
                <includeScope>runtime</includeScope>
                <excludeArtifactIds>azure-functions-java-library</excludeArtifactIds>
            </configuration>
        </execution>
    </executions>
</plugin>
like image 28
Vijayendra Vasu Avatar answered Nov 15 '22 21:11

Vijayendra Vasu