Create Java applications with IBM Cloud Functions

For a description of IBM Cloud Functions itself, see Creating a PHP application with IBM Cloud Functions-Qiita.

Hello World

Created using IntelliJ IDEA (hereinafter abbreviated as IntelliJ). The environment uses Mac.

Open IntelliJ and click "Create New Project" or create a project from "File"-"New"-"Project".

Select Gradle on the left, check Java on the right, and click Next.

image.png

The Groupid can be empty if you do not plan to deploy it to the Maven repository. Enter the project name in ArtifactId. Here, it is sample-java. Leave the default version.

image.png

Check Use auto-import.

image.png

Finish with the Project name and Project location as they are.

When Finished, Gradle's initial processing is performed, and the directory structure is as follows.

image.png

Right-click on the src --main --java directory and create a Java Class.

image.png

The name is Sample.

Refer to the code in Java sample for creating and launching Cloud Functions actions.

import com.google.gson.JsonObject;
public class Sample {
    public static JsonObject main(JsonObject args) {
        String name = "stranger";
        if (args.has("name"))
            name = args.getAsJsonPrimitive("name").getAsString();
        JsonObject response = new JsonObject();
        response.addProperty("greeting", "Hello " + name + "!");
        return response;
    }
}

To Sample.java. Add gson to dependencies in build.gradle to import gson.

version '1.0-SNAPSHOT'

apply plugin: 'java'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    compile 'com.google.code.gson:gson:2.6.2'  //to add
    testCompile group: 'junit', name: 'junit', version: '4.12'
}

Once added, gson will be installed.

Now let's take a look at build.gradle.

Set the version of this project with version.

apply plugin: 'java'

Set the Java plugin with [^ 1]. Now you can use the settings and tasks used in Java. The directory structure created by creating an IntelliJ project

└── src/
    ├── main/
    │   ├── java/
    │   └── resources/
    └── test/
        ├── java/
        └── resources/

But this is the Java plugin's default project layout

src/main/Java source for java products
src/main/resources Product resources
src/test/Java source for java test
src/test/resources Test resources

It has become.

Set repositories to use Maven central repository.

Write dependency libraries in dependencies. Write compile-time dependencies in compile and additional compile-time dependencies for tests in testCompile. The writing style is different between compile and testCompile, but the writing style of compile is

compile group: 'com.google.code.gson', name: 'gson', version: '2.6.2'

Abbreviated version of. Gradle settings are written in Groovy, but Groovy allows you to omit the method parentheses, so I don't put parentheses in compile. Since it cannot be omitted if there is no argument, it is attached to mavenCentral ().

You can check the version, apply, sourceCompatibility, repositories, and dependencies set here in Project.

Now, make a jar. Click Gradle on the right side of IntelliJ to bring up the Gradle projects window.

image.png

If you execute "Tasks"-"build"-"jar", you will get a jar called sample-java-1.0-SNAPSHOT.jar in build / libs.

Or there is a file called gradlew in the project directory, so use this

$ ./gradlew jar

But you can create a jar. gradlew is called a gradle wrapper, which downloads gradle binaries if needed.

Let's check the contents of the jar.

$ jar -tf build/libs/sample-java-1.0-SNAPSHOT.jar
META-INF/
META-INF/MANIFEST.MF
Sample.class

-t is an option to display the contents of the archive, -f is a file specification.

A jar is a compressed file in zip format.

$ file build/libs/sample-java-1.0-SNAPSHOT.jar
build/libs/sample-java-1.0-SNAPSHOT.jar: Zip archive data, at least v1.0 to extract

By the way, the contents of the compressed file can be viewed in Vim.

$ vim build/libs/sample-java-1.0-SNAPSHOT.jar
" zip.vim version v28
" Browsing zipfile /Users/tmsanrinsha/IdeaProjects/sample-java/build/libs/sample-java-1.0-SNAPSHOT.jar
" Select a file with cursor and press ENTER

META-INF/
META-INF/MANIFEST.MF
Sample.class

Place the cursor on the line META-INF / MANIFEST.MF and press Enter

Manifest-Version: 1.0

The contents are displayed as.

Upload action.

$ bx wsk action create sample-java build/libs/sample-java-1.0-SNAPSHOT.jar --main Sample

Execute.

$ bx wsk action invoke sample-java --result
{
    "greeting": "Hello stranger!"
}

Set the parameters and execute.

$ bx wsk action invoke sample-java --result -p name reader
{
    "greeting": "Hello reader!"
}

If there are dependent libraries

$ jar -tf build/libs/sample-java-1.0-SNAPSHOT.jar
META-INF/
META-INF/MANIFEST.MF
Sample.class

Looking at the contents of the jar, Gson is not included. However, Gson works even if it's not provided by IBM Cloud Functions.

Building OpenWhisk actions with Java and Gradle-IBM Cloud Blog with dependent libraries There is an example.

Rewrite Sample.java as follows. This is a program that returns the received text as a QR code.

import java.io.*;
import java.util.Base64;
import com.google.gson.JsonObject;
import com.google.zxing.*;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;

public class Sample {

    public static JsonObject main(JsonObject args) throws Exception {
        String text = args.getAsJsonPrimitive("text").getAsString();

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        OutputStream b64os = Base64.getEncoder().wrap(baos);

        BitMatrix matrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, 300, 300);

        MatrixToImageWriter.writeToStream(matrix, "png", b64os);

        b64os.close();

        String output = baos.toString("utf-8");
        JsonObject response = new JsonObject();
        response.addProperty("qr", output);

        return response;
    }
}

Rewrite build.gradle as follows.

version '1.0-SNAPSHOT'

apply plugin: 'java'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

configurations {
    provided
    compile.extendsFrom provided
}

dependencies {
    provided 'com.google.code.gson:gson:2.6.2'
    compile 'com.google.zxing:core:3.3.0'
    compile 'com.google.zxing:javase:3.3.0'
    testCompile group: 'junit', name: 'junit', version: '4.12'
}

jar {
    dependsOn configurations.runtime
    from {
        (configurations.runtime - configurations.provided).collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }
}

The setting of this gradle is based on Fat Jars with Excluded Dependencies in Gradle.

First,

configurations {
    provided
    compile.extendsFrom provided
}

Define a provided in and [ʻextends From`](https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.Configuration.html#org.gradle.api.artifacts. Inherit compile from provided using Configuration: extendsFrom (org.gradle.api.artifacts.Configuration [])).

In dependencies, those that do not need to be included in the jar are defined in provided, and those that are included are defined in compile. Since compile depends on provided, the dependency written in provided is also included at compile time.

I'm dependsOn with jar, but it worked without it, so I don't know if it's there.

[from](https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html#org.gradle.api.tasks.bundling.Jar:from(java. lang.Object [])) is used to set the files to be included in the jar. Included in from is configurations.runtime minus configurations.provided. According to dependency configurations, runtime inherits compile, so compile isAnd theprovided dependency is entered, and it is subtracted by provided, so only the compile` dependency remains.

Make a jar,

$ ./gradlew jar
$ jar -tf build/libs/sample-java-1.0-SNAPSHOT.jar

If you do, you can see that libraries other than Gson are included.

update

$ bx wsk action update sample-java build/libs/sample-java-1.0-SNAPSHOT.jar --main Sample

Execute

$ bx wsk action invoke sample-java --result -p text 'Hello world!'
{
    "qr": "iVBORw0KGgoAAAANSUhEUgAAASwAAAEsAQAAAABRBrPYAAABHElEQVR42u3aPRKCMBCG4VBxDI5KjpojWFIR2ezyEx3Uwiyj86ZwgjxU32w2/IT8ybgFGAwGg8F+ik3BxpDnMOapy9H+6GB+TI9yHGSWepkdT8CcWJRgooalF0
h2sEvYHhbsOiY52QUwf5brQnm3vsEasK2JT1Y3b3o9rAGrRlxPvt73wr7NJgumRDTK4Zj6WX5gfkxGEpG0bo4VBPNidfsIS07lNm+ZZZgfs4iWsMoFs9ZNGDLMj+mYrUaShvW8lYI5MItt1JNldtbrYQ3YoV8Ys9u8HubItvYha5a2871uYG5
sf7xhD8D7sr3qYFcwa+JBbzBOw4I1Zw/vImBubH8ZtNZNeLG+wVqw6qFf/UIC5sX4HAIGg8Fgf8Pu1ACAFLpztaIAAAAASUVORK5CYII="
}

The result will come back properly. To make this a png

bx wsk action invoke sample-java --result -p text 'Hello world!' | jq -r .qr | base64 -d > qr.png

As

$ open qr.png

Then the QR code will be displayed.

Create a method for debugging

Add public static void main (String [] args) so that you can mess with ʻargs of public static JsonObject main (JsonObject args) `.

public class Sample {

    public static void main(String[] args) throws Exception {
        String str;
        if (args.length == 0) {
            str = "{\"text\":\"Hello stranger\"}";
        } else {
            str = args[0];
        }
        JsonObject jsonArgs = new JsonParser().parse(str).getAsJsonObject();
        System.out.println(main(jsonArgs).toString());
    }

    public static JsonObject main(JsonObject args) throws Exception {
// ...
    }
}

Now, if an argument is given and executed, the first argument is executed, otherwise str is used to executepublic static JsonObject main (JsonObject args).

If you create a method of public static void main (String [] args), you can execute it by putting a ▶ mark on the left side of the IntelliJ code and clicking it.

If you want to set the argument, you can set it from "Run"-"Edit Configurations ...". However, it would be easier to fix the str in the code.

If you want to run it in Gradle, add the following to build.gradle.

// ...
apply plugin: 'java'
apply plugin: 'application' //add to

mainClassName = 'Sample' //add to

sourceCompatibility = 1.8
// ...

The Application Plugin allows you to use a task called run to run an application. The main class name is set with mainClassName.

with this

$ ./gradlew run

Can be executed with. You can also run it from Tasks --application --run in the Gradle projects window.

However, it is not possible to pass arguments directly with gradle task. According to Gradle task --pass arguments to Java application --Stack Overflow

run {
    if (project.hasProperty("appArgs")) {
        args Eval.me(appArgs)
    }
}

To build.gradle

$ ./gradlew run -PappArgs='"{\"text\":\"a\"}"'

Can be executed with arguments.

Manage with Git

The following files are not needed, so write them in .gitignore.

.gitignore


.gradle/
.idea/
build/

When importing, specify the URL of GitHub etc. in "File"-"New"-"Project from Version Control". Unlinked Gradle project? Will appear, so I'll do an Import Gradle project.

Instead of importing from Version Control, you can git clone, select" File "-" New "-" Project from Existing Sources ... ", and select Gradle in" Import Gradle project ".

Sample made this time

Reference material

-Introduction to Gradle-Official Help | IntelliJ IDEA --Java sample for creating and launching Cloud Functions actions -Chapter 23 Java Plugin

[^ 1]: Chapter 23 Java Plugin, The Java Plugin --Gradle User Manual .org / current / userguide / java_plugin.html). Please note that Japanese is old.

Recommended Posts

Create Java applications with IBM Cloud Functions
Use Java 11 with Google Cloud Functions
Create an immutable class with JAVA
Easily Docker Java applications with Jib
[Java] Create an executable module with Gradle
CICS-Run Java applications-(2) Build management with Maven
Beginners create web applications with Java and MySQL (adding at any time)
Try using Firebase Cloud Functions on Android (Java)
Create a CSR with extended information in Java
[Windows] [IntelliJ] [Java] [Tomcat] Create a Tomcat9 environment with IntelliJ
Let's create a timed process with Java Timer! !!
Build and test Java + Gradle applications with Wercker
[Java] Create a collection with only one element
Get along with Java containers in Cloud Run
Create Spring Cloud Config Server with security with Spring Boot 2.0
How to call functions in bulk with Java reflection
[Beginner] Create a competitive game with basic Java knowledge
I dealt with Azure Functions not working in Java
[Note] Create a java environment from scratch with docker
Serverless Java EE starting with Quarkus and Cloud Run
Install java with Homebrew
Try create with Trailblazer
Change seats with java
[Java] Create a filter
Comfortable download with JAVA
Switch java with direnv
Download Java with Ansible
Create JSON in Java
Let's scrape with Java! !!
Build Java with Wercker
Endian conversion with JAVA
I tried to create a java8 development environment with Chocolatey
Create a SlackBot with AWS lambda & API Gateway in Java
Initial setting method when making Alexa Skill with JAVA (Cloud9)
I want to implement various functions with kotlin and java!
Create a simple DRUD application with Java + SpringBoot + Gradle + thymeleaf (1)
[Java] Sample project for developing web applications with Spring Boot
Upload files to Aspera that comes with IBM Cloud Object Storage (ICOS) using SDK (Java version)