tag:blogger.com,1999:blog-183133362024-03-28T08:40:36.999-04:00Abhi On Javaabhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.comBlogger231125tag:blogger.com,1999:blog-18313336.post-36757143679485657972017-10-14T11:13:00.000-04:002017-10-14T11:13:15.948-04:00Deploy Java Web Application on Heroku with Heroku CLIThis post will describe how to create and deploy a Java Web Application war to Heroku using Heroku CLI. You will need a basic understanding of Git and Maven, and have Git and Maven already installed on your system.
<h5>Pre-requisites</h5><ul><li>Install Java 8, Maven and Git. For this post, I used <b>Java 8</b> and <b>Maven 3.5</b>.</li><li>Create a free account on heroku.com. This account will be used from Heroku CLI to login</li><li>Download and Install Heroku CLI from <a href="https://devcenter.heroku.com/articles/heroku-cli">here</a>.</li></ul>
Following are the high-level steps to follow<ol><li>Create a Simple Spring Web Application.</li><li>Create an application on Heroku</li><li>Create the Procfile</li><li>Create app.json</li><li>Update Maven pom.xml</li><li>Push code to Heroku</li></ol><a name='more'></a><h4>Create a Simple Spring Web Application</h4>We will use a very basic spring boot web application which will show a Hello World Screen. We will have only two Java files<ul><li>SpringWebApplication.java: This is the spring boot main class</li><li>HelloWorld: This is a simple Spring Controller which will print Hellow World to the screen.</li></ul> The following is the folder structure.<h5>HelloWorld.java</h5><pre><code>package com.blogspot.javax.springweb;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloWorld {
@RequestMapping("/")
public String index() {
return "Hello World";
}
}</code></pre><h5>SpringWebApplication.java</h5><pre><code>package com.blogspot.javax.springweb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
@SpringBootApplication
public class SpringWebApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SpringWebApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(SpringWebApplication.class, args);
}
}</code></pre>The maven <code>pom.xml</code> file is at the end of this post.
<h4>Create a Heroku Application using Heroku CLI</h4>Follow these steps to create a heroku application.<ol><li>Open up a command line and login to heroku using the credentials of your heroku account<pre><code>C:\workspaces\aoj\spring-web>heroku login
Enter your Heroku credentials:
Email: ******@******.***
Password: ********
Logged in as ******@******.***</code></pre></li><li>Create an application on Heroku using <code>heroku create</code> command. You can pass any name, and heroku will create the app if the name is available. If you do not pass any name, heroku will pick a name for you, and you can rename it later.<pre><code>C:\workspaces\aoj\spring-web>heroku create <APP-NAME-HERE>
Creating <APP-NAME-HERE>... done
https://<APP-NAME-HERE>.herokuapp.com/ | https://git.heroku.com/<APP-NAME-HERE>.git</code></pre></li></ol><h4>Create the Procfile</h4>A Procfile is a mechanism for declaring what commands are run by your application’s dynos on the Heroku platform. The name "Procfile" should be used as is, without extensions and is case-sensitive. This file has to be place in the application root directory. For our simple Web application, we will use webapprunner, which can be used for tomcat based applications<pre><code>web: java $JAVA_OPTS -jar target/dependency/webapp-runner.jar --port $PORT target/*.war</code></pre>Here we specify that it is a web application and the command to be run is the webapp-runner.jar.<h4>app.json</h4>This file can be used to describe the application details, setup configurations and runtime environments in a structured way. In our example, we just print the application name and description in this file. The app.json file should also be at the root folder of the application<pre><code>{
"name": "Spring Web",
"description": "Spring Boot WebApp"
}</code></pre><h4>Add the WebAppRunner plugin to Maven</h4>Add the following plugin to Maven pom.xml<pre><code><build>
<plugins>
.......
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>com.github.jsimone</groupId>
<artifactId>webapp-runner</artifactId>
<version>8.5.23.0</version>
<destFileName>webapp-runner.jar</destFileName>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build></code></pre><h4>Push Code to Heroku to Deploy</h4>You can push the code to Heroku. And based on the pom.xml, Heroku will detect that this is a Java project and attempt to deploy it.<pre><code>C:\workspaces\aoj\spring-web>git add .
warning: LF will be replaced by CRLF in .mvn/wrapper/maven-wrapper.properties.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in pom.xml.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in src/test/java/com/blogspot/javax/springweb/SpringWebApplicationTests.java.
The file will have its original line endings in your working directory.
C:\workspaces\aoj\spring-web>git commit -m "initial"
[master c911ee8] initial
2 files changed, 134 insertions(+), 31 deletions(-)
create mode 100644 out.txt
C:\workspaces\aoj\spring-web>git push heroku master</code></pre>Once deployed, Heroku will give you the URL at the end of the command as shown below.<pre><code>remote: [INFO] ------------------------------------------------------
remote: [INFO] BUILD SUCCESS
remote: [INFO] ------------------------------------------------------
remote: [INFO] Total time: 6.173 s
remote: [INFO] Finished at: 2017-10-14T15:07:16+00:00
remote: [INFO] Final Memory: 34M/297M
remote: [INFO] ------------------------------------------------------
remote: -----> Discovering process types
remote: Procfile declares types -> web
remote:
remote: -----> Compressing...
remote: Done: 92.7M
remote: -----> Launching...
remote: Released v5
remote: https://<b><APP-NAME-HERE></b>.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/<b><APP-NAME-HERE></b>.git
02fac92..c911ee8 master -> master</code></pre>
<h4>Folder Structure</h4><pre><code>
spring-web
│ .classpath
│ .gitignore
│ .project
│ <b>app.json</b>
│ out.txt
│ <b>pom.xml</b>
│ <b>Procfile</b>
│
├───.mvn
│ └───wrapper
│ maven-wrapper.jar
│ maven-wrapper.properties
│
├───.settings
│ org.eclipse.core.resources.prefs
│ org.eclipse.jdt.core.prefs
│ org.eclipse.m2e.core.prefs
│
└───src
├───main
│ ├───java
│ │ └───com
│ │ └───blogspot
│ │ └───javax
│ │ └───springweb
│ │ HelloWorld.java
│ │ SpringWebApplication.java
│ │
│ └───resources
│ │ application.properties
│ │
│ ├───static
│ └───templates
└───test
└───java
└───com
└───blogspot
└───javax
└───springweb
SpringWebApplicationTests.java</code></pre>
<h4>Full pom.xml</h4><pre><code><?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.blogspot.java-x</groupId>
<artifactId>spring-web</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>spring-web</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.7.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.3.7.v20160115</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>com.github.jsimone</groupId>
<artifactId>webapp-runner</artifactId>
<version>8.5.23.0</version>
<destFileName>webapp-runner.jar</destFileName>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
</code></pre>abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com129tag:blogger.com,1999:blog-18313336.post-18220652147540612982017-10-08T17:01:00.001-04:002017-10-08T17:01:44.227-04:00Jenkins Offline Install on Red Hat Enterprise Linux ServerIn this post we will see how to do an offline install Jenkins and required plugins on a Red Hat Enterprise Linux Server release 7.3. This is likely the case when your server is behind a firewall. But you have access to internet from your workspace. The assumption here is that you have sudo access on the server to do the install. Follow these steps...<a name='more'></a>
<ol><li>Make sure you have Java 8 or higher installed on your server and that JAVA_HOME is set, as well as $JAVA_HOME/bin is in PATH</li><li>Download the RPM key for jenkins from <a href="https://jenkins-ci.org/redhat/jenkins-ci.org.key">https://jenkins-ci.org/redhat/jenkins-ci.org.key</a>.</li><li>Import the key<pre><code>sudo rpm --import jenkins-ci.org.key</code></pre></li><li>Download the rpm package for the Jenkins version you want to install from <a href="http://pkg.jenkins.io/redhat-stable/">http://pkg.jenkins.io/redhat-stable/</a>. </li><li>Install Jenkins using the following command<pre><code>sudo yum install jenkins-2.73.1-1.1.noarch.rpm</code></pre></li></ol><h5>Jenkins Installation Folder on Red Hat Enterprise Linux Server release 7.3</h5>Once you are done with the above steps, Jenkins will be installed in <code>/var/lib/jenkins</code> folder. You will also be able to see the jenkins.war file in /usr/lib/jenkins folder.<h5>Start and Stop Jenkins manually</h5>To start and stop Jenkins manually instead of using systemctl, you can use the following commands <pre><code>sudo service jenkins start</code></pre><pre><code>sudo service jenkins stop</code></pre><h5>Setup Jenkins Plugins in Offline Mode</h5>To install plugins in offline mode, you have download the .hpi plugin file from <a href="https://updates.jenkins-ci.org/download/plugins/">https://updates.jenkins-ci.org/download/plugins/</a>. However, if you go this route, you will have to download the dependencies too, which can make this task near impossible. The easier way is to <ol><li>Install Jenkins and the related plugins on your workstation, or any other machine (It can be Windows machine too).</li><li>Once all the plugins are downloaded, you can copy the plugins folder from the workstation to the Jenkins server /var/lib/jenkins folder. </li><li>After you copy, just stop and start Jenkins, and you will see that all your plugins are installed.</li></ol>abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com23tag:blogger.com,1999:blog-18313336.post-6383615858374456652017-10-08T17:01:00.000-04:002017-10-08T17:01:36.923-04:00Build Git From Source Code on Red Hat Enterprise Linux ServerRedhat Enterprise Linux provides <a href="https://developers.redhat.com/products/developertoolset/overview/">Redhat Developer Toolset</a>, which allows you to install Git. However, it is usually an older version. If you want the latest version of Git on your Server, then building Git from sources is the easiest way. Follow these steps to install Git from sources on Red Hat Enterprise Linux Server release 7.3. <b><u>On our server, the following commands were run by the root user.</u></b><a name='more'></a><ol><li>To install Git from source code, you must need to have the following libraries and tools that Git depends on: gcc, perl-ExtUtils-MakeMaker, autotools, curl, zlib, openssl, expat, and libiconv. Run the following commands to install these requirements<pre><code>yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel</code></pre><pre><code>yum install gcc perl-ExtUtils-MakeMaker</code></pre></li><li>Download the latest Git sources from <a href="https://www.kernel.org/pub/software/scm/git/">https://www.kernel.org/pub/software/scm/git/</a></li><li>Extract the source code into /usr/src<pre><code>cp git-2.9.4.tar.gz /usr/src/
cd /usr/src/
tar xzf git-2.9.4.tar.gz</code></pre></li><li>Run the following commands to install git<pre><code>cd git-2.9.4
make prefix=/usr/local/git all
make prefix=/usr/local/git install</code></pre></li></ol>Once you are done with these steps, you should be able to run git commands normally as shown below<pre><code>git clone git://git.kernel.org/pub/scm/git/git.git</code></pre>abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com14tag:blogger.com,1999:blog-18313336.post-55050449289415627492017-10-07T04:06:00.001-04:002017-10-07T04:35:35.403-04:00Weblogic Remote Deploy from Red Hat Enterprise Linux Server: Unknown object in LOCATE_REQUESTRecently I was attempting to deploy to weblogic from a Jenkins installed on a <u>Red Hat Enterprise Linux Server release 7.3</u>, to a remote Weblogic 12.1.3 cluster. Which was failing with a <code>org.omg.CORBA.OBJECT_NOT_EXIST</code>. Eventually, I ended up trying to do a manual deploy using the ANT task <code>wldeploy</code>, with the following command <pre><code> ant -lib /apps/wls12130/wlserver/server/lib deploy -Dweblogic.user=adminuser -Dweblogic.password=adminpassword -Dadminurl=t3://admin-server:admin-port -Dweblogic.cluster=ClusterName</code></pre> As you can see from the command, we are passing command-line arguments which specify the location and credentials for the remote cluster. On the Linux machine to with the <code>[wldeploy] Caused by: javax.naming.NamingException: Couldn't connect to the specified host [Root exception is org.omg.CORBA.OBJECT_NOT_EXIST: Unknown object in LOCATE_REQUEST vmcid: 0x0 minor code: 0 completed: No]</code> error. Following is the full stacktrace, followed by a cause and resolution to this problem...<a name='more'></a><pre><code> [wldeploy] Exception in thread "main" weblogic.Deployer$DeployerException: weblogic.deploy.api.tools.deployer.DeployerException: Unable to connect to 't3://adminserver:adminport': Unknown object in LOCATE_REQUEST. Ensure the url represents a running admin server and that the credentials are correct. If using http protocol, tunneling must be enabled on the admin server.
[wldeploy] at weblogic.Deployer.run(Deployer.java:76)
[wldeploy] at weblogic.Deployer.mainWithExceptions(Deployer.java:63)
[wldeploy] at weblogic.ant.taskdefs.management.DeployerWrapper.main(DeployerWrapper.java:14)
[wldeploy] Caused by: weblogic.deploy.api.tools.deployer.DeployerException: Unable to connect to 't3://adminserver:adminport': Unknown object in LOCATE_REQUEST. Ensure the url represents a running admin server and that the credentials are correct. If using http protocol, tunneling must be enabled on the admin server.
[wldeploy] at weblogic.deploy.api.tools.deployer.Jsr88Operation.connect(Jsr88Operation.java:317)
[wldeploy] at weblogic.deploy.api.tools.deployer.Deployer.perform(Deployer.java:137)
[wldeploy] at weblogic.deploy.api.tools.deployer.Deployer.runBody(Deployer.java:88)
[wldeploy] at weblogic.utils.compiler.Tool.run(Tool.java:158)
[wldeploy] at weblogic.utils.compiler.Tool.run(Tool.java:115)
[wldeploy] at weblogic.Deployer.run(Deployer.java:74)
[wldeploy] ... 2 more
[wldeploy] Caused by: javax.enterprise.deploy.spi.exceptions.DeploymentManagerCreationException: [J2EE Deployment SPI:260010]Unable to connect to "t3://adminserver:adminport" as user, "adminuser". Error received: Couldn't connect to the specified host
[wldeploy] at weblogic.deploy.api.spi.deploy.WebLogicDeploymentManagerImpl.<init>(WebLogicDeploymentManagerImpl.java:137)
[wldeploy] at weblogic.deploy.api.spi.factories.internal.DeploymentFactoryImpl.getDeploymentManager(DeploymentFactoryImpl.java:86)
[wldeploy] at weblogic.deploy.api.tools.SessionHelper.getRemoteDeploymentManager(SessionHelper.java:530)
[wldeploy] at weblogic.deploy.api.tools.deployer.Jsr88Operation.connect(Jsr88Operation.java:298)
[wldeploy] ... 7 more
[wldeploy] Caused by: weblogic.deploy.api.spi.exceptions.ServerConnectionException: [J2EE Deployment SPI:260010]Unable to connect to "t3://adminserver:adminport" as user, "adminuser". Error received: Couldn't connect to the specified host
[wldeploy] at weblogic.deploy.api.spi.deploy.internal.ServerConnectionImpl.getMBeanServer(ServerConnectionImpl.java:258)
[wldeploy] at weblogic.deploy.api.spi.deploy.internal.ServerConnectionImpl.getMBeanServerForType(ServerConnectionImpl.java:198)
[wldeploy] at weblogic.deploy.api.spi.deploy.internal.ServerConnectionImpl.init(ServerConnectionImpl.java:148)
[wldeploy] at weblogic.deploy.api.spi.deploy.WebLogicDeploymentManagerImpl.getNewConnection(WebLogicDeploymentManagerImpl.java:164)
[wldeploy] at weblogic.deploy.api.spi.deploy.WebLogicDeploymentManagerImpl.<init>(WebLogicDeploymentManagerImpl.java:134)
[wldeploy] ... 10 more
[wldeploy] Caused by: java.io.IOException: Couldn't connect to the specified host
[wldeploy] at weblogic.management.remote.common.ClientProviderBase.makeConnection(ClientProviderBase.java:237)
[wldeploy] at weblogic.management.remote.common.ClientProviderBase.newJMXConnector(ClientProviderBase.java:120)
[wldeploy] at javax.management.remote.JMXConnectorFactory.newJMXConnector(JMXConnectorFactory.java:371)
[wldeploy] at javax.management.remote.JMXConnectorFactory.connect(JMXConnectorFactory.java:269)
[wldeploy] at weblogic.deploy.api.spi.deploy.internal.ServerConnectionImpl.getMBeanServer(ServerConnectionImpl.java:247)
[wldeploy] ... 14 more
[wldeploy] Caused by: javax.naming.NamingException: Couldn't connect to the specified host [Root exception is org.omg.CORBA.OBJECT_NOT_EXIST: Unknown object in LOCATE_REQUEST vmcid: 0x0 minor code: 0 completed: No]
[wldeploy] at weblogic.corba.j2ee.naming.Utils.wrapNamingException(Utils.java:83)
[wldeploy] at weblogic.corba.j2ee.naming.ORBHelper.getORBReferenceWithRetry(ORBHelper.java:638)
[wldeploy] at weblogic.corba.j2ee.naming.ORBHelper.getORBReference(ORBHelper.java:582)
[wldeploy] at weblogic.corba.j2ee.naming.InitialContextFactoryImpl.getInitialContext(InitialContextFactoryImpl.java:85)
[wldeploy] at weblogic.corba.j2ee.naming.InitialContextFactoryImpl.getInitialContext(InitialContextFactoryImpl.java:31)
[wldeploy] at weblogic.jndi.WLInitialContextFactory.getInitialContext(WLInitialContextFactory.java:46)
[wldeploy] at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:684)
[wldeploy] at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:313)
[wldeploy] at javax.naming.InitialContext.init(InitialContext.java:244)
[wldeploy] at javax.naming.InitialContext.<init>(InitialContext.java:216)
[wldeploy] at weblogic.management.remote.common.ClientProviderBase.makeConnection(ClientProviderBase.java:221)
[wldeploy] ... 18 more
[wldeploy] Caused by: org.omg.CORBA.OBJECT_NOT_EXIST: Unknown object in LOCATE_REQUEST vmcid: 0x0 minor code: 0 completed: No
[wldeploy] at weblogic.iiop.LocateReplyMessage.needsForwarding(LocateReplyMessage.java:171)
[wldeploy] at weblogic.iiop.IORManager.locateInitialReference(IORManager.java:251)
[wldeploy] at weblogic.corba.orb.ORB.resolve_initial_references(ORB.java:258)
[wldeploy] at weblogic.corba.client.naming.ClientORBInfo.<init>(ClientORBInfo.java:34)
[wldeploy] at weblogic.corba.client.naming.ClientORBHelper.createORBInfo(ClientORBHelper.java:42)
[wldeploy] at weblogic.corba.j2ee.naming.ORBHelper.cacheORB(ORBHelper.java:310)
[wldeploy] at weblogic.corba.j2ee.naming.ORBHelper.cacheORBAndCreateURL(ORBHelper.java:319)
[wldeploy] at weblogic.corba.j2ee.naming.ORBHelper.getORBReferenceWithRetry(ORBHelper.java:622)
[wldeploy] ... 27 more
[wldeploy] webLogic.Deployer execution failed</code></pre>Weblogic admin server and the managed servers in the cluster were in RUNNING state without any problems.
<h3>Cause for : Unknown object in LOCATE_REQUEST vmcid: 0x0 minor code: 0 completed: No</h3>
Although it doesn't mention in the exception stack trace, this error was <b><u>caused by the missing libraries in the classpath</u></b>. This was made explicit when we try to use the WLST PING, to ping the server using the following command.<pre><code>java -cp /apps/wls12130/wlserver/server/lib/ weblogic.Admin -url t3://adminserver:adminport -username adminuser -password adminpassword PING</code></pre>Running this command throws an explicit CLASSPATH error as shown below<pre><code>Error: Could not find or load main class weblogic.Admin</code></pre> Clearly, setting the server/lib in the classpath was not enough. This error will obviously happen with other utilities such as weblogic.Deployer or weblogic.Server etc.
<h3>Fix for : Unknown object in LOCATE_REQUEST vmcid: 0x0 minor code: 0 completed: No</h3>
To fix this issue, we have to set the environment such as PATH and CLASSPATH properly. Luckily, Weblogic offers a <code>setWLSEnv.sh</code> script that sets up the environment as required for WLST commands. Follow these steps to attempt to fix this issue.<ol><li>Set the MW_HOME variable to the Weblogic server home directory. For Weblogic 12.1.3, this was MW_HOME, however if you are using Weblogic 12.2, you may have to set the ORACLE_HOME to the Weblogic home directory (I did not try Weblogic 12.2 though).<pre><code>export MW_HOME=/apps/wls12130/</code></pre></li><li>Run the setWLSEnv.sh script<pre><code>. $MW_HOME/wlserver/server/bin/setWLSEnv.sh</code></pre></li></ol>Once run this script, you should be able to run the previous command without setting the classpath explicitly.<pre><code>java weblogic.Admin -url t3://adminserver:adminport -username adminuser -password adminpassword PING</code></pre><pre><code>ant deploy -Dweblogic.user=adminuser -Dweblogic.password=adminpassword -Dadminurl=t3://admin-server:admin-port -Dweblogic.cluster=ClusterName</code></pre>
abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com10tag:blogger.com,1999:blog-18313336.post-3034466936834932082017-10-04T23:23:00.000-04:002017-10-04T23:23:00.443-04:00Java 9: Reactive programming with Flow APIIn a previous post about <a href="/2017/07/reactor-reactive-programming-java-8.html">Reactive programming with Java 8</a>, we looked into reactive programming support by Reactor. Java 9 introduced reactive programming in Java with the Flow API. In this post, we will look at how the various components in the Flow API work with a few examples.<a name='more'></a> Reactive programming primarily deals with processing asynchronous streams where the application reacts to incoming stream of data. Since reactive programming model deals with streams of incoming data, there is no need to store data in memory (like a list) and iterate over the data. This results in reduction in memory usage.<h5>Java 9 Flow API</h5>The Java 9 Flow API is built around the java.util.concurrent.Flow class, which defines 4 interfaces.<ul><li><b>static interface Flow.Publisher<T> :</b> The purpose of the publisher is to produce data and related control messages to the subscribers.</li><li><b>static interface Flow.Subscriber<T>:</b> Subscribers subscribe to a Publisher to consume data produced by the Publisher</li><li><b>static interface Flow.Subscription:</b> Subscription represents the link between a Publisher and Subscriber.</li><li><b>static interface Flow.Processor<T,R>:</b> Processor is a component which can act as a producer and consumer simultaneously.</li></ul>In the following examples we will see how to use each of these interfaces.<h5>Publisher</h5>A publisher publishes the stream of data to the corresponding subscribers. Java 9 provides an implementation of the Publisher interface: <code>SubmissionPublisher</code>. You can initialize a publisher as shown below<pre><code>SubmissionPublisher<String> publisher = new SubmissionPublisher<>();</code></pre><h5>Subscriber</h5>We use a Subscriber to subscribe to the data that is being published by a publisher. We are required to implement <code>java.util.concurrent.Flow.Subscriber</code> interface and provide implementation for the abstract methods. In the following example of a custom Subscriber that I created, a few things are important to note.<ul><li>You can see that in the <code>onSubscribe()</code> and <code>onNext()</code> methods we make a call to <code>subscription.request(1)</code>. This is because without call to request() method, the subscriber will not accept any data from the publisher.</li><li>A subscriber can cancel at any time using the <code>cancel()</code> method. In this example, we cancel after processing 4 events.</li></ul><pre><code>package com.aoj.java9.reactive;
import java.util.concurrent.Flow.Subscriber;
import java.util.concurrent.Flow.Subscription;
public class MySubscriber<T> implements Subscriber<String> {
private Subscription subscription;
private int i = 0;
@Override
public void onComplete() {
System.out.println("Complete");
}
@Override
public void onError(Throwable e) {
System.out.println("Error ");
e.getStackTrace();
}
@Override
public void onNext(String str) {
System.out.println("String : " + str);
i++;
if (i > 3) {
System.out.println("Cancelling subscription on i = " + i);
subscription.cancel();
}
subscription.request(1);
}
@Override
public void onSubscribe(Subscription sub) {
this.subscription = sub;
System.out.println(sub);
subscription.request(1);
}
}</code></pre><h5>Subscription</h5>Subscription represents the link between the publisher and subscriber. A subscription is created when we call the <code>subscribe()</code> method on a Publisher as shown below<pre><code>SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
Subscriber<String> subscriber = new MySubscriber<String>();
publisher.subscribe(subscriber);</code></pre><h5>Using Publisher and Subscriber together</h5>The following class makes use of the <code>MySubscriber</code> class and uses the <code>SubmissionPublisher</code> publish a stream of strings from a list. <ul><li>The <code>Thread.sleep</code> is used, since this is an asynchronous model and this simple program will end before the subscriber gets to process the data. We wait for 1 second, for the subscriber to complete here.</li><li><code>publisher.close()</code> is used to close the stream. In this example, it might not make much sense, but in an interactive scenario, it will be advisable to close the publisher at the appropriate time.</li></ul><pre><code>package com.aoj.java9.reactive;
import java.util.List;
import java.util.concurrent.Flow.Subscriber;
import java.util.concurrent.SubmissionPublisher;
public class ReactorTest {
public static void main(String[] args) {
List<String> strings = List.of("one", "two", "three", "four", "five");
SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
Subscriber<String> subscriber = new MySubscriber<String>();
publisher.subscribe(subscriber);
strings.forEach(str -> publisher.submit(str));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
publisher.close();
}
}</code></pre>abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com4tag:blogger.com,1999:blog-18313336.post-9285046949724136692017-10-03T23:49:00.001-04:002017-10-03T23:49:45.606-04:00Java 9 : Private interface methodsJava 8 introduced default and static methods, the previous post gives a few examples of <a href="/2017/10/java-8-interfaces-default-and-static.html">Java 8 default and static methods</a>. Java 9 builds on that foundation and adds support for private interface methods. In this post, we will see a simple example of how to use private methods to interfaces. In general, <ol><li>Like any private method, private interface methods are accessible from within the enclosing interface only. </li><li>Private methods can be declared using the <code>private</code> keyword.</li><li>Any <code>private</code> method has to be implemented in the interface as it cannot implemented in a sub-interface or implementing classes.</li></ol>
<a name='more'></a>
The following example shows how to create a private method in the interface and a default method calling it.<pre><code>package interfaces;
public interface InterfaceA {
default String hello(String str) {
return privateAddon("InterfaceA : hello " + str);
}
private String privateAddon(String str) {
return "Private Addon : " + str;
}
}</code></pre>The following is a simple implementation class of this interface<pre><code>package interfaces;
public class PrivateInterfaceMethods implements InterfaceA {
public static void main(String[] args) {
PrivateInterfaceMethods example = new PrivateInterfaceMethods();
System.out.println(example.hello("world"));
}
}</code></pre>abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com1tag:blogger.com,1999:blog-18313336.post-75299900322655314392017-10-03T23:31:00.000-04:002017-10-03T23:31:44.922-04:00Java 8 Interfaces: default and static methodsJava 8 introduces default static methods that enable you to add new functionality to the interfaces of your libraries and ensure binary compatibility with code written for older versions of those interfaces. While both static and default methods allow to add method implementations to interfaces, the difference is that you cannot override static methods. Both default and static methods are "public", and there is no need to explicitly declare them as public.<a name='more'></a><h4>Default Interface Methods</h4>Default methods in interfaces allow you to add default implementation to methods that you can use as is, or override. But adding method implementation to interface introduces the problem of the classic multiple inheritance problem in C++ that was one of the main reasons for introducing interfaces in Java. Java avoids that problem by making it a compile time error if you introduce the classic "Diamond" inheritance while implementing multiple interfaces. If you extend create a diamond inheritance structure, Java 8 forces you to implement the method that is inherited multiple times through different interface. We will take a look at that behavior in the following example.
<h5>Create default methods</h5>Default methods can be created by simply defining the method with the <code>default</code> keyword.<pre><code>package interfaces;
public interface InterfaceA {
String add(int a, int b);
String subtract(int a, int b);
default String hello(String str) {
return "InterfaceA : " + str;
}
}</code></pre>We will use the following two interfaces to demonstrate the behavior of in case of multiple inheritance. Both <code>InterfaceB</code> and <code>InterfaceC</code> extend <code>InterfaceA</code>, but will implement different methods as <code>default</code> methods. Finally, we will create an implementation class that implements both InterfaceB and InterfaceC.<h6>InterfaceB</h6><pre><code>package interfaces;
public interface InterfaceB extends InterfaceA {
@Override
default String add(int a, int b) {
return "InterfaceB Add : " + (a + b);
}
String subtract(int a, int b);
}</code></pre><h6>InterfaceC</h6><pre><code>package interfaces;
public interface InterfaceC extends InterfaceA {
String add(int a, int b);
@Override
default String subtract(int a, int b) {
return "InterfaceC : " + (a + b);
}
}</code></pre><h5>Implementation class and the super keyword</h5>The implementation class <code>DefaultMethodsExample</code> implements InterfaceB and InterfaceC. However, since there is a conflict, Java 8 forces you to implement the <code>add()</code> and <code>subtract()</code>. And since there is no conflict with the <code>hello()</code> methods, we don't have to implement it. You will also notice what you can use the <code>InterfaceC.super</code> call in the the subtract method can be used to invoke the specific Interface you want the implementation to come from.<pre><code>package interfaces;
public class DefaultMethodsExample implements InterfaceB, InterfaceC {
@Override
public String subtract(int a, int b) {
return InterfaceC.super.subtract(a, b);
}
@Override
public String add(int a, int b) {
return "DefaultMethodsExample : " + (a + b);
}
public static void main(String[] args) {
DefaultMethodsExample example = new DefaultMethodsExample();
System.out.println(example.hello("world"));
System.out.println(example.add(1, 2));
System.out.println(example.subtract(6, 5));
}
}</code></pre><h4>Static Interface Methods</h4>Static methods are also public like default methods, but you cannot override the static methods. The following example shows one use of the static method. We will create a static method in InterfaceA from the above example as shown below<pre><code>package interfaces;
public interface InterfaceA {
String add(int a, int b);
String subtract(int a, int b);
default String hello(String str) {
return "InterfaceA : hello " + str;
}
static String staticHello(String str) {
return "InterfaceA Static : hello " + str;
}
}</code></pre>To invoke the static method <code>staticHello()</code>, we can invoke it like any static method of a class <code>InterfaceA.staticHello</code> as shown below.<pre><code>package interfaces;
public class DefaultMethodsExample implements InterfaceB, InterfaceC {
@Override
public String subtract(int a, int b) {
return InterfaceC.super.subtract(a, b);
}
@Override
public String add(int a, int b) {
return "DefaultMethodsExample : " + (a + b);
}
public static void main(String[] args) {
DefaultMethodsExample example = new DefaultMethodsExample();
System.out.println(example.hello("world"));
System.out.println(example.add(1, 2));
System.out.println(example.subtract(6, 5));
System.out.println(InterfaceA.staticHello("World"));
}
}</code></pre>abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com7tag:blogger.com,1999:blog-18313336.post-44542245433180202352017-10-02T15:21:00.000-04:002017-10-02T15:21:15.460-04:00Java 9 Date Time API ChangesJava 9 added a few enhancements to the new Date and Time API which was introduced in Java 8. We will go over a few of these additions to LocalDate and LocalTime in this post
<ul><li>Stream<LocalDate> datesUntil(LocalDate endExclusive) // LocalDate</li><li>public Stream<LocalDate> datesUntil(LocalDate endExclusive, Period step) //LocalDate</li><li>public long toEpochSecond(LocalTime time, ZoneOffset offset) //LocalDate</li><li>toEpochSecond(LocalDate date, ZoneOffset offset) //LocalTime</li></ul>
<a name='more'></a>
<h4>Getting a stream of Dates with datesUntil</h4>
The <code>datesUntil()</code> method has two variations, the first one takes end date and gives a list of dates between the current date and end date, while the second one take a Period object as a parameter that provides a way to skip dates and Stream only a select subset of the dates between start and end dates.<br />For the first example, we will just print all the dates between today and December 31, 2017.<pre><code>Stream<LocalDate> dates = LocalDate.now().datesUntil(LocalDate.parse("2017-12-31"));
dates.forEach(System.out::println);</code></pre>In the next couple of examples, we will use the second variation or <code>datesUntil</code> method to print alternate days and days apart by a week.<pre><code>Stream<LocalDate> alternateDays = LocalDate.now().datesUntil(LocalDate.parse("2017-12-31"), Period.ofDays(2));
alternateDays.forEach(System.out::println);
Stream<LocalDate> weekly = LocalDate.now().datesUntil(LocalDate.parse("2017-12-31"), Period.ofWeeks(1));
weekly.forEach(System.out::println);</code></pre>
<h4>Number of milliseconds from epoch of 1970-01-01T00:00:00Z with toEpochSecond()</h4>Since both LocalDate and LocalTime do not contain the time and date respectively, in order to convert them to Epochtime, we have to pass the LocalTime and LocalDate to the toEpochTime. The following two examples show how to use these methods<pre><code>LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now();
System.out.println("LocalDate toEpochSecond : " + date.toEpochSecond(time, ZoneOffset.of("Z")));
System.out.println("LocalTime toEpochSecond : " + time.toEpochSecond(date, ZoneOffset.of("Z")));</code></pre><h4>Full code</h4><pre><code>package com.aoj.java9.base;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Period;
import java.time.ZoneOffset;
import java.util.stream.Stream;
public class Java9DateTime {
public static void main(String[] args) {
Stream<LocalDate> dates = LocalDate.now().datesUntil(LocalDate.parse("2017-12-31"));
dates.forEach(System.out::println);
Stream<LocalDate> alternateDays = LocalDate.now().datesUntil(LocalDate.parse("2017-12-31"), Period.ofDays(2));
alternateDays.forEach(System.out::println);
Stream<LocalDate> weekly = LocalDate.now().datesUntil(LocalDate.parse("2017-12-31"), Period.ofWeeks(1));
weekly.forEach(System.out::println);
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now();
System.out.println("LocalDate toEpochSecond : " + date.toEpochSecond(time, ZoneOffset.of("Z")));
System.out.println("LocalTime toEpochSecond : " + time.toEpochSecond(date, ZoneOffset.of("Z")));
}
}</code></pre>abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com0tag:blogger.com,1999:blog-18313336.post-15322229424647149162017-09-29T22:19:00.003-04:002017-09-29T22:19:51.572-04:00Java 8 Date Time API: LocalTimeWith Java 8 Oracle introduced new Date and Time APIs which address the shortcomings of the existing java.util.Date and java.util.Calendar.
In this article we will take a look at the Java 8 Date and Time API with few examples of the new LocalTime class introduced by Java 8.
<h3>Improvements to Existing Calendar and Date Classes</h3>
Thread Safety: The existing API was not designed with concurrency in mind. This meant developers had to come up with custom solutions to handle thread safety. The Java 8 Date/Time API ensures thread safety by making all the new classes immutable.
Domain-driven design: The Java 8 date/time API has clear domain boundaries, and defines classes with specific use cases.
Support for non-standard Calendars: The Java 8 Date/Time API provides support for non-standard calendaring systems (Japanese calendar for example) without affecting the standard calendar implementation.<a name='more'></a>
<h3>LocalTime</h3>
<code>java.time.LocalTime</code>, like LocalDate, represents the Time, without the Date.
The following examples show show a few ways to use the LocalTime class
<ul>
<li><b>Create an instance of LocalTime for current time:</b> The instance representing current time can be obtained using the <code>now()</code> method<pre><code>LocalTime localTime = LocalTime.now();</code></pre></li>
<li><b>Create an instance of LocaTime representing a specific time:</b> Again, like LocalDate, there are two variations in which you can instantiate LocalTime to represent a specific time: <ul><li>The <code>LocalTime.of</code> method takes the distinct elements of the time as parameters (hours, minutes, seconds etc.). The following variants are available<pre><code>static LocalTime of(int hour, int minute)
static LocalTime of(int hour, int minute, int second)
static LocalTime of(int hour, int minute, int second, int nanoOfSecond)</code></pre> The following example shows the use of this method<pre><code>LocalTime specificTime1 = LocalTime.of(21, 30); // 9:30 PM
System.out.println(specificTime1);</code></pre></li><li>The second method is <code>LocalTime.parse</code> which again has two variations<ul><li>The default format is <code>HH:mm:ss.nnn</code>. The first variant of <code>parse</code>, takes just a string representation of the date and attempts to parse the date by the default format. We can omit the trailing sections of the time, and still be able to parse the time.<pre><code>LocalTime specificTime2 = LocalTime.parse("21:30:33.435");
System.out.println("With LocalTime.parse, and default format : " + specificTime2);
LocalTime specificTime3 = LocalTime.parse("21:30:33");
System.out.println("With LocalTime.parse, and default format and remove nanoseconds : " + specificTime3);</code></pre></li><li>Custom Time Format: In this variation, we can use custom formatting using <code>DateTimeFormatter.ofPattern</code>. In the following example, we will use the parse method to parse a simple time format ("09:30 PM")<pre><code>DateTimeFormatter dateTimeFormat = DateTimeFormatter.ofPattern("hh:mm a");
LocalTime specificTime4 = LocalTime.parse("09:30 PM", dateTimeFormat);
System.out.println("With LocalTime.parse, and custom format : " + specificTime4); </code></pre></li></ul></li></ul></li><li><b>Get parts of the time:</b> LocalTime also provides a few utility method to extract part of the time and get more information about the date<pre><code>System.out.println("Hour of the day : " + localTime.getHour());
System.out.println("Minute of the hour : " + localTime.getMinute());</code></pre></li>
<li><b>Add or Subtract with LocalTime:</b> LocalTime class provides utility methods to add or subtract hours/minutes/seconds (represented by <code>java.time.temporal.TemporalUnit</code> interface). The following examples illustrate the use of these operation on LocalTime.<pre><code>//Subtract Hours
System.out.println("3 hours before now is : " + localTime.minus(3, ChronoUnit.HOURS));
//Subtract Minutes
System.out.println("3 minutes before now is : " + localTime.minus(3, ChronoUnit.MINUTES));
//Add Hours
System.out.println("3 hours after now is : " + localTime.plus(3, ChronoUnit.HOURS));
//Add Minutes
System.out.println("3 minutes after now is : " + localTime.plus(3, ChronoUnit.MINUTES));</code></pre></li>
<li><b>Compare two LocalTimes:</b> The <code>isBefore</code> and <code>isAfter</code> offer a way to compare two LocalTime objects<pre><code>System.out.println("Is the time after 11:26? " + localTime.isAfter(LocalTime.parse("11:26")));
System.out.println("Is the time before 11:30? " + localTime.isBefore(LocalTime.parse("11:30")));</code></pre></li>
<li><b>Time between two LocalTimes:</b> The <code>until()</code> method provides a way to calculate the number of hours/minutes etc between two LocalTimes. This method takes in the end time and TemporalUnit as a parameter, and can be used to calculate the number hours, minutes etc. between the start time and end time.<pre><code>System.out.println("Number of hours from now to 11:30: " + localTime.until(LocalTime.parse("11:30"), ChronoUnit.HOURS));
System.out.println("Number of minutes from now to 11:30: " + localTime.until(LocalTime.parse("11:30"), ChronoUnit.MINUTES));</code></pre></li></ul>abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com0tag:blogger.com,1999:blog-18313336.post-66796201704166052512017-09-29T22:19:00.002-04:002017-09-29T22:19:45.590-04:00Java 8 Date And Time API:Time ZonesIn the previous three posts, we took a detailed look at the Java 8 Local Date and Time classes. In this post, we will take a look at the Java 8 provides ZonedDateTime and OffsetDateTime classes.
<h3>ZonedDateTime</h3>
ZonedDateTime uses ZoneId to represent different time zones. The following example shows how to create a ZoneId for Chicago<pre><code>ZoneId zoneId = ZoneId.of("America/Chicago");</code></pre>Following piece of code shows how to obtain a list of all zone ids.<pre><code>Set<String> zoneIdList = ZoneId.getAvailableZoneIds();</code></pre>There are many ways to instantiate ZonedDateTime, most of them parallel LocalDateTime as shown in the previous post, with the addition of Zone Id.<pre><code>ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, zoneId);
ZonedDateTime.parse("2015-05-03T10:15:30+01:00[America/Los_Angeles]");</code></pre><h5>Truncate Time from ZonedDateTime</h5>The <code>truncateTo()</code> method can be used to truncate the time fields. Any Time Unit lesser than the passed parameter will be marked to zero.<pre><code>// Anything under days is set to zero. Works only for time.
System.out.println(zonedDateTime + " Truncated to " + zonedDateTime.truncatedTo(ChronoUnit.HOURS));</code></pre><h5>Convert Time Zone</h5>Converting time from one timezone to another is one of the common requirements. The <code></code> method of ZonedDateTime can be used to convert a given ZonedDateTime to any timzone. The following example can be used to convert the current time in Chicago timezone to time in Los_Angeles<pre><code>// Convert Time Zone
System.out.println(zonedDateTime + " in Los Angeles " + zonedDateTime.withZoneSameInstant(ZoneId.of("America/Los_Angeles")));</code></pre>
ZonedDateTime also offers many of the same utility methods offered by LocalDateTime. A few examples are shown below<pre><code>System.out.println("3 days before today is : " + zonedDateTime.minus(3, ChronoUnit.DAYS));
System.out.println("3 decades before today is : " + zonedDateTime.minus(3, ChronoUnit.DECADES));
System.out.println("3 days after today is : " + zonedDateTime.plus(3, ChronoUnit.DAYS));
System.out.println("3 decades after today is : " + zonedDateTime.plus(3, ChronoUnit.DECADES));
System.out.println("The day of the week is : " + zonedDateTime.getDayOfWeek());
System.out.println("The day of the year is : " + zonedDateTime.getDayOfYear());</code></pre>
<h3>OffsetDateTime</h3>
OffsetDateTime class can be used to represent DateTime with an Offset. This class stores all date and time fields, to a precision of nanoseconds, as well as the offset from UTC/Greenwich. For example, the value "2nd October 2007 at 13:45.30.123456789 +02:00" can be stored in an OffsetDateTime. OffsetDateTime can be created in the following ways.<pre><code>// Now
OffsetDateTime offsetDateTime = OffsetDateTime.now();
System.out.println("OffsetDateTime : " + offsetDateTime);
// Get LocalDateTime and apply Offset
LocalDateTime localDateTime = LocalDateTime.of(2017, Month.SEPTEMBER, 29, 5, 30);
ZoneOffset offset = ZoneOffset.of("+02:00");
OffsetDateTime offSetByTwo = OffsetDateTime.of(localDateTime, offset);
System.out.println(localDateTime + " Offset by two " + offSetByTwo);
</code></pre><h3>Full code for this post</h3><pre><code>import java.time.LocalDateTime;
import java.time.Month;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
public class ZonedDateTimeExamples {
public static void main(String[] args) {
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("America/Chicago"));
System.out.println(zonedDateTime);
// Convert Time Zone
System.out
.println(zonedDateTime + " in Los Angeles " + zonedDateTime.withZoneSameInstant(ZoneId.of("America/Los_Angeles")));
// Anything under days is set to zero. Works only for time.
System.out.println(zonedDateTime + " Truncated to " + zonedDateTime.truncatedTo(ChronoUnit.HOURS));
System.out.println("3 days before today is : " + zonedDateTime.minus(3, ChronoUnit.DAYS));
System.out.println("3 decades before today is : " + zonedDateTime.minus(3, ChronoUnit.DECADES));
System.out.println("3 days after today is : " + zonedDateTime.plus(3, ChronoUnit.DAYS));
System.out.println("3 decades after today is : " + zonedDateTime.plus(3, ChronoUnit.DECADES));
System.out.println("The day of the week is : " + zonedDateTime.getDayOfWeek());
System.out.println("The day of the year is : " + zonedDateTime.getDayOfYear());
// Now
OffsetDateTime offsetDateTime = OffsetDateTime.now();
System.out.println("OffsetDateTime : " + offsetDateTime);
// Get LocalDateTime and apply Offset
LocalDateTime localDateTime = LocalDateTime.of(2017, Month.SEPTEMBER, 29, 5, 30);
ZoneOffset offset = ZoneOffset.of("+02:00");
OffsetDateTime offSetByTwo = OffsetDateTime.of(localDateTime, offset);
System.out.println(localDateTime + " Offset by two " + offSetByTwo);
}
}</code></pre>abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com0tag:blogger.com,1999:blog-18313336.post-13053523747668508842017-09-29T22:19:00.001-04:002017-09-29T22:19:40.075-04:00Java 8 Date And Time API: LocalDateWith Java 8 Oracle introduced new Date and Time APIs which address the shortcomings of the existing java.util.Date and java.util.Calendar.
In this article we will take a look at the Java 8 Date and Time API with few examples of the new LocalDate class introduced by Java 8.
<h3>Improvements to Existing Calendar and Date Classes</h3>
Thread Safety: The existing API was not designed with concurrency in mind. This meant developers had to come up with custom solutions to handle thread safety. The Java 8 Date/Time API ensures thread safety by making all the new classes immutable.
Domain-driven design: The Java 8 date/time API has clear domain boundaries, and defines classes with specific use cases.
Support for non-standard Calendars: The Java 8 Date/Time API provides support for non-standard calendaring systems (Japanese calendar for example) without affecting the standard calendar implementation.
<a name='more'></a>
<h3>LocalDate</h3>
The LocalDate represents a date in yyyy-mm-dd format. Unlike it's predecessor Date, LocalDate does not store the time.
The following few examples show how you can use the <code>java.time.LocalDate</code> class
<ul>
<li><b>Create an instance of LocalDate for today:</b> The <code>LocalDate.now()</code> method can be used to obtain an instance of LocalDate representing the current date.<pre><code>LocalDate localDate = LocalDate.now();</code></pre></li>
<li><b>Create an instance of LocalDate for any specific date:</b> There are a couple of ways in which you can obtain an instance of LocalDate representing a specific date<ul><li>The <code>LocalDate.of()</code> method takes the year, month, and day as arguments in that order. All are integer values<pre><code>LocalDate specificDate1 = LocalDate.of(2017, 1, 1);</code></pre></li><li>The <code>LocalDate.parse()</code> method again has a couple of options, the first one takes in the default format (yyyy-MM-dd) as input and tries to parse it. In the second variation, you can pass the <code>java.time.format.DateTimeFormatter</code> specifying the format in which you expect the date.<pre><code> LocalDate specificDate2 = LocalDate.parse("2017-01-01"); //2017-1-1 will fail as the default format is expected to be yyyy-mm-dd
System.out.println(specificDate2);
DateTimeFormatter dateTimeFormat = DateTimeFormatter.ofPattern("MM-dd-yyyy");
LocalDate specificDate3 = LocalDate.parse("12-01-2017", dateTimeFormat);
System.out.println(specificDate3);</code></pre></li></ul></li>
<li><b>Add or Subtract with LocalDate:</b> LocalDate class provides utility methods to add or subtract days/months/years (represented by <code>java.time.temporal.TemporalUnit</code> interface). The following examples illustrate the use of Date arithmetic on LocalDate.<pre><code>LocalDate localDate = LocalDate.now();
// Subtract Days
System.out.println("3 days before today is : " + localDate.minus(3, ChronoUnit.DAYS));
// Subtract Decades
System.out.println("3 decades before today is : " + localDate.minus(3, ChronoUnit.DECADES));
// Add Days
System.out.println("3 days after today is : " + localDate.plus(3, ChronoUnit.DAYS));
// Add Decades
System.out.println("3 decades after today is : " + localDate.plus(3, ChronoUnit.DECADES));</code></pre></li>
<li><b>Get parts of the date:</b> LocalDate also provides a few utility methods to extract part of the date and get more information about the date, like the day of the week, day of the year etc.<pre><code>// Day of the Week
System.out.println("The day of the week is : " + localDate.getDayOfWeek());
// Day of the year
System.out.println("The day of the year is : " + localDate.getDayOfYear());
System.out.println("Is this a Leap Year? " + localDate.isLeapYear());</code></pre></li>
<li><b>Compare two LocalDates:</b> The <code>isBefore</code>, <code>isAfter</code>, and <code>isEqual</code> methods offer a way to compare two LocalDate objects<pre><code>System.out.println("Is today after 2017-12-12? " + localDate.isAfter(LocalDate.parse("2017-12-12")));
System.out.println("Is today after 2017-12-12? " + localDate.isBefore(LocalDate.parse("2017-12-12")));
System.out.println("Is today 2017-12-12? " + localDate.isEqual(LocalDate.parse("2017-12-12")));</code></pre></li><li><b>Days between two Dates:</b> The <code>until()</code> method provides a couple variants that can be used to calculate the number of days/months/yearts etc between two LocalDates. The first variant takes just one parameter (the endDate), and calculates the Period between the start and end dates, the Period will shows the number of years, months and days between the start and end dates. The second variation takes in the TemporalUnit as a parameter, and can be used to calculate the number Months, Years etc. between the start date and end date.<pre><code>// Period between two dates
System.out.println("Number of days from now to 2017-12-12: " + localDate.until(LocalDate.parse("2017-12-12"))); //Variant 1: Will print something like P2M10D, which is short for 2months and 10 days.
// Days between two dates
System.out.println("Number of days from now to 2017-12-12: " + localDate.until(LocalDate.parse("2017-12-12"), ChronoUnit.DAYS));
// Months between two dates
System.out.println("Number of days from now to 2017-12-12: " + localDate.until(LocalDate.parse("2017-12-12"), ChronoUnit.MONTHS));</code></pre></li><li><b>Date Boundaries:</b> The <code>with()</code> method can be used to identify the first of the month/year etc. of a given LocalDate. The <code>with()</code> method takes a TemporalAdjuster as a parameter as shown below.<pre><code>// First day of this month
System.out.println("First day of this month is : " + localDate.with(TemporalAdjusters.firstDayOfMonth()));
// First day of next month
System.out.println("First day of next month is : " + localDate.with(TemporalAdjusters.firstDayOfNextMonth()));
// Last day of this month
System.out.println("Last day of this month is : " + localDate.with(TemporalAdjusters.lastDayOfMonth()));</code></pre></li></ul><h3>Full Code</h3><pre><code>import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
public class LocalDateExamples {
public static void main(String[] args) {
LocalDate specificDate1 = LocalDate.of(2017, 1, 1);
System.out.println(specificDate1);
LocalDate specificDate2 = LocalDate.parse("2017-01-01"); // 2017-1-1 will fail as the default format is expected to be yyyy-MM-dd
System.out.println(specificDate2);
DateTimeFormatter dateTimeFormat = DateTimeFormatter.ofPattern("MM-dd-yyyy");
LocalDate specificDate3 = LocalDate.parse("12-01-2017", dateTimeFormat);
System.out.println(specificDate3);
LocalDate localDate = LocalDate.now();
System.out.println("3 days before today is : " + localDate.minus(3, ChronoUnit.DAYS));
System.out.println("3 decades before today is : " + localDate.minus(3, ChronoUnit.DECADES));
System.out.println("3 days after today is : " + localDate.plus(3, ChronoUnit.DAYS));
System.out.println("3 decades after today is : " + localDate.plus(3, ChronoUnit.DECADES));
System.out.println("The day of the week is : " + localDate.getDayOfWeek());
System.out.println("The day of the year is : " + localDate.getDayOfYear());
System.out.println("Is this a Leap Year? " + localDate.isLeapYear());
System.out.println("Is today after 2017-12-12? " + localDate.isAfter(LocalDate.parse("2017-12-12")));
System.out.println("Is today after 2017-12-12? " + localDate.isBefore(LocalDate.parse("2017-12-12")));
System.out.println("Is today 2017-12-12? " + localDate.isEqual(LocalDate.parse("2017-12-12")));
System.out.println("Number of days from now to 2017-12-12: " + localDate.until(LocalDate.parse("2017-12-12"), ChronoUnit.DAYS));
System.out.println("Number of days from now to 2017-12-12: " + localDate.until(LocalDate.parse("2017-12-12")));
System.out.println("Number of days from now to 2017-12-12: " + localDate.until(LocalDate.parse("2017-12-12"), ChronoUnit.MONTHS));
System.out.println("First day of this month is : " + localDate.with(TemporalAdjusters.firstDayOfMonth()));
System.out.println("First day of next month is : " + localDate.with(TemporalAdjusters.firstDayOfNextMonth()));
System.out.println("Last day of this month is : " + localDate.with(TemporalAdjusters.lastDayOfMonth()));
}
}</code></pre>abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com0tag:blogger.com,1999:blog-18313336.post-27329731321962938422017-09-29T22:19:00.000-04:002017-09-29T22:19:34.712-04:00Java 8 Date Time API: LocalDateTimeWith Java 8 Oracle introduced new Date and Time APIs which address the shortcomings of the existing java.util.Date and java.util.Calendar.
In this article we will take a look at the Java 8 Date and Time API with few examples of the new LocalDateTime class introduced by Java 8.
<h3>Improvements to Existing Calendar and Date Classes</h3>
Thread Safety: The existing API was not designed with concurrency in mind. This meant developers had to come up with custom solutions to handle thread safety. The Java 8 Date/Time API ensures thread safety by making all the new classes immutable.
Domain-driven design: The Java 8 date/time API has clear domain boundaries, and defines classes with specific use cases.
Support for non-standard Calendars: The Java 8 Date/Time API provides support for non-standard calendaring systems (Japanese calendar for example) without affecting the standard calendar implementation.<a name='more'></a>
<h3>LocalDateTime</h3>
<code>java.time.LocalDateTime</code>, like LocalDate, represents the Time, without the Date.
The following examples show show a few ways to use the LocalDateTime class
<ul>
<li><b>Create an instance of LocalDateTime for current time:</b> The instance representing current time can be obtained using the <code>now()</code> method<pre><code>LocalDateTime localDateTime = LocalDateTime.now();</code></pre></li>
<li><b>Create an instance of LocalDateTime representing a specific time:</b> Again, like LocalDate, there are two variations in which you can instantiate LocalDateTime to represent a specific time: <ul><li>The <code>LocalDateTime.of</code> method takes the distinct elements of the date and time as parameters (year, month, day, hours, minutes, seconds etc.). The following variants are available<pre><code>static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute)
static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second)
static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond)
static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute)
static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second)
static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond)
static LocalDateTime of(LocalDate date, LocalTime time)
static LocalDateTime ofEpochSecond(long epochSecond, int nanoOfSecond, ZoneOffset offset)</code></pre> The following example shows the use of this method<pre><code>LocalDateTime specificDateTime1 = LocalDateTime.of(2017, Month.MAY, 21, 21, 30); // 05/21/2017 9:30 PM
System.out.println(specificDateTime1);</code></pre></li><li>The second method is <code>LocalDateTime.parse</code> which again has two variations<ul><li>The default format is <code>DateTimeFormatter.ISO_LOCAL_DATE_TIME</code>, for example : 2017-05-21T21:30:00. The first variant of <code>parse</code>, takes just a string representation of the date and attempts to parse the date by the default format. We can omit the trailing sections of the time, and still be able to parse the time.<pre><code>LocalDateTime specificDateTime2 = LocalDateTime.parse("2017-05-21T21:30:00");
System.out.println("With LocalDateTime.parse, and default format : " + specificDateTime2);</code></pre></li><li>Custom Date Time Format: In this variation, we can use custom formatting using <code>DateTimeFormatter.ofPattern</code>. In the following example, we will use the parse method to parse a simple time format ("09:30 PM")<pre><code>DateTimeFormatter dateTimeFormat = DateTimeFormatter.ofPattern("MM-dd-yyyy hh:mm a");
LocalDateTime specificDateTime4 = LocalDateTime.parse("05-21-2017 09:30 PM", dateTimeFormat);
System.out.println("With LocalDateTime.parse, and custom format : " + specificDateTime4);</code></pre></li></ul></li></ul></li><li><b>Get parts of the date time:</b> LocalDateTime also provides a few utility method to extract part of the time and get more information about the date<pre><code>System.out.println("Hour of the day : " + localDateTime.getHour());
System.out.println("Minute of the hour : " + localDateTime.getMinute());</code></pre></li>
<li><b>Add or Subtract with LocalDateTime:</b> LocalDateTime class provides utility methods to add or subtract hours/minutes/seconds (represented by <code>java.time.temporal.TemporalUnit</code> interface). The following examples illustrate the use of these operation on LocalDateTime.<pre><code>//Subtract Days
System.out.println("3 days before now is : " + localDateTime.minus(3, ChronoUnit.DAYS));
//Subtract Minutes
System.out.println("3 minutes before now is : " + localDateTime.minus(3, ChronoUnit.MINUTES));
//Add Days
System.out.println("3 days after now is : " + localDateTime.plus(3, ChronoUnit.DAYS));
//Add Minutes
System.out.println("3 minutes after now is : " + localDateTime.plus(3, ChronoUnit.MINUTES));</code></pre></li>
<li><b>Compare two LocalDateTimes:</b> The <code>isBefore</code> and <code>isAfter</code> offer a way to compare two LocalDateTime objects<pre><code>System.out.println("Is the time after 11:26? " + localDateTime.isAfter(LocalDateTime.parse("2017-05-21T21:30:00")));
System.out.println("Is the time before 11:30? " + localDateTime.isBefore(LocalDateTime.parse("2017-05-21T21:30:00")));</code></pre></li>
<li><b>Time between two LocalDateTimes:</b> The <code>until()</code> method provides a way to calculate the number of hours/minutes etc between two LocalDateTimes. This method takes in the end time and TemporalUnit as a parameter, and can be used to calculate the number hours, minutes etc. between the start time and end time.<pre><code>System.out.println("Number of hours from now to 2018-05-21T21:30:00: " + localDateTime.until(LocalDateTime.parse("2018-05-21T21:30:00"), ChronoUnit.HOURS));
System.out.println("Number of minutes from now to 2018-05-21T21:30:00: " + localDateTime.until(LocalDateTime.parse("2018-05-21T21:30:00"), ChronoUnit.MINUTES));</code></pre></li></ul><h3>Full Class file for this test</h3><pre><code>import java.time.LocalDateTime;
import java.time.Month;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
public class LocalDateTimeExamples {
public static void main(String[] args) {
LocalDateTime specificTime1 = LocalDateTime.of(2017, Month.MAY, 21, 21, 30); // 9:30 PM
System.out.println("With LocalDateTime.of : " + specificTime1);
LocalDateTime specificDateTime2 = LocalDateTime.parse("2017-05-21T21:30:00");
System.out.println("With LocalDateTime.parse, and default format : " + specificDateTime2);
DateTimeFormatter dateTimeFormat = DateTimeFormatter.ofPattern("MM-dd-yyyy hh:mm a");
LocalDateTime specificDateTime4 = LocalDateTime.parse("05-21-2017 09:30 PM", dateTimeFormat);
System.out.println("With LocalDateTime.parse, and custom format : " + specificDateTime4);
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("Hour of the day : " + localDateTime.getHour());
System.out.println("Minute of the hour : " + localDateTime.getMinute());
// Subtract Days
System.out.println("3 days before now is : " + localDateTime.minus(3, ChronoUnit.DAYS));
// Subtract Minutes
System.out.println("3 minutes before now is : " + localDateTime.minus(3, ChronoUnit.MINUTES));
// Add Days
System.out.println("3 days after now is : " + localDateTime.plus(3, ChronoUnit.DAYS));
// Add Minutes
System.out.println("3 minutes after now is : " + localDateTime.plus(3, ChronoUnit.MINUTES));
System.out.println("Is the time after 11:26? " + localDateTime.isAfter(LocalDateTime.parse("2017-05-21T21:30:00")));
System.out.println("Is the time before 11:30? " + localDateTime.isBefore(LocalDateTime.parse("2017-05-21T21:30:00")));
System.out.println("Number of hours from now to 2018-05-21T21:30:00: "
+ localDateTime.until(LocalDateTime.parse("2018-05-21T21:30:00"), ChronoUnit.HOURS));
System.out.println("Number of minutes from now to 2018-05-21T21:30:00: "
+ localDateTime.until(LocalDateTime.parse("2018-05-21T21:30:00"), ChronoUnit.MINUTES));
}
}</code></pre>abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com0tag:blogger.com,1999:blog-18313336.post-58304724041843880042017-09-29T11:28:00.000-04:002017-09-29T11:28:08.675-04:00Java 9 Streams : dropWhile()In Java 9, comes with a few good additions to the Stream API. For more information on the Java 8 Streams, go to the Java 8 Page. The following new methods were added to the Java 9 Stream API.
<ol><li>dropWhile</li><li>dropWhile</li><li>iterate</li><li>ofNullable</li></ol>
In this post we will take a look at the dropWhile() method.
<a name='more'></a>
<h3>dropWhile() method</h3>
In Stream API, dropWhile() Method takes a Predicate(function returning true or false) as an argument, and drops the set of elements of the stream that match the Predicate and returns the rest of the elements. However, this behavior varies between ordered and unordered streams. <pre><code>Stream<T> dropWhile(Predicate<? super T> predicate)</code></pre>In all the examples below, We will use the following list as a starting point, unless mentioned otherwise.
<pre><code>List<String> list = List.of("returns", "if", "this", "stream", "is", "ordered,", "stream", "consisting", "of", "the",
"longest", "prefix", "of", "elements", "taken", "from", "this", "stream", "that", "match", "the", "given",
"predicate");</code></pre>
As you can see, the sorted version of the list will look like this<pre><code>consisting, elements, from, given, if, is, longest, match, of, of, ordered,, predicate, prefix, returns, stream, stream, stream, taken, that, the, the, this, this</code></pre>
<h3>For Ordered Stream</h3>
From the Javadoc<quote>If this stream is ordered then the longest prefix is a contiguous sequence of elements of this stream that match the given predicate. The first element of the sequence is the first element of this stream, and the element immediately following the last element of the sequence does not match the given predicate.</quote>
This effectively means that if for an ordered list, dropWhile() will return all values if the first element doesn't match the predicate. You can see this behavior in the following example where we Predicate is to check if the length of a string is less than 4. Since the first element of the sorted stream "consists" is longer than 4 characters, we get back all elements of the Stream<pre><code> list
.stream()
.sorted()
.dropWhile(x -> x.length() < 4)
.forEach(System.out::println);</code></pre>
However, if the first element of the stream matches the predicate, then it will drop the first few elements of the Stream that match the predicate, and return the remaning elements. As soon as the predicate returns false, dropWhile() stops, even if there are any subsequent elements that match the predicate further downstream. In the following example, we check for strings length greater than 2, which will return "if, is, longest, match, of, of, ordered,, predicate, prefix, returns, stream, stream, stream, taken, that, the, the, this, this", which is the list of elements starting with the first element "if" that matches the predicate.<pre><code>list
.stream()
.sorted()
.dropWhile(x -> x.length() >2)
.forEach(x-> System.out.print(x + ", "));
Output:
"if, is, longest, match, of, of, ordered,, predicate, prefix, returns, stream, stream, stream, taken, that, the, the, this, this, </code></pre>
Another example<pre><code>list
.stream()
.sorted()
.dropWhile(x -> x.contains("c"))
.forEach(x-> System.out.print(x + ", "));
Output:
elements, from, given, if, is, longest, match, of, of, ordered,, predicate, prefix, returns, stream, stream, stream, taken, that, the, the, this, this, </code></pre>
<h3>For Unordered Stream</h3>
From the Javadoc<quote>If this stream is unordered, and some (but not all) elements of this stream match the given predicate, then the behavior of this operation is nondeterministic; it is free to take any subset of matching elements (which includes the empty set).</quote>
<pre><code>list
.stream()
.dropWhile(x -> x.contains("t"))
.forEach(x-> System.out.print(x + ", "));
Output:
if, this, stream, is, ordered,, stream, consisting, of, the, longest, prefix, of, elements, taken, from, this, stream, that, match, the, given, predicate, </code></pre>The following Stream of number where we check for number less than 7,<pre><code>Stream.of(1,5,3,2,4,9,7)
.dropWhile(x->x <7)
.forEach(System.out::println);
Output:
9
7</code></pre>
<h3>Here is the full code</h3><pre><code>package com.aoj.java9.collections;
import java.util.List;
import java.util.stream.Stream;
public class Java9StreamsDropWhile {
public static void main(String[] args) {
List<String> list = List.of("returns", "if", "this", "stream", "is", "ordered,", "stream", "consisting", "of", "the",
"longest", "prefix", "of", "elements", "taken", "from", "this", "stream", "that", "match", "the", "given",
"predicate");
list.stream().sorted().forEach(x-> System.out.print(x + ", "));
System.out.println();
list
.stream()
.sorted()
.dropWhile(x -> x.length() >2)
.forEach(x-> System.out.print(x + ", "));
list
.stream()
.sorted()
.dropWhile(x -> x.contains("c"))
.forEach(x-> System.out.print(x + ", "));
list
.stream()
.sorted()
.dropWhile(x -> x.length() < 4)
.forEach(System.out::println);
list
.stream()
.dropWhile(x -> x.contains("t"))
.forEach(x-> System.out.print(x + ", "));
Stream.of(1,5,3,2,4,9,7)
.dropWhile(x->x <7)
.forEach(System.out::println);
}
}</code></pre>
abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com0tag:blogger.com,1999:blog-18313336.post-55515832912369620662017-09-28T08:40:00.000-04:002017-09-28T08:40:33.473-04:00Java 9 Streams: iterate() and ofNullable() methodsIn Java 9, comes with a few good additions to the Stream API. For more information on the Java 8 Streams, go to the Java 8 Page. The following new methods were added to the Java 9 Stream API.
<ol><li>dropWhile</li><li>dropWhile</li><li>iterate</li><li>ofNullable</li></ol>
In this post we will take a look at the <code>iterate()</code> and <code>ofNullable()</code> methods.<a name='more'></a>
<h3>Java 9 Stream iterate()</h3>
The new iterate() method in Java 9 is in addition to the Java 8 <code>iterate()</code> method. Both methods can be used to generate a stream of elements, but the new variation adds a predicate, which will determine when the iteration stops. <pre><code>static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)</code></pre>In a way this performs similar to the <code>for</code> loop. In this example, we iterate over number starting from the seed (0) and incremenent by 1(n -> n + 1) with a predicate that will stop when n=10 (n->10).<pre><code>Stream<Integer> stream2 = Stream.iterate(0, n -> n < 10, n -> n + 1);
stream2.forEach(x -> System.out.print(x + ", "));
System.out.println();
Output
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,</code></pre>The same functionality can be achieved by the Java 8 version of the iterator using the limit function as shown below. <pre><code>Stream<Integer> stream1 = Stream.iterate(0, n -> n + 1).limit(10);
stream1.forEach(x -> System.out.print(x + ", "));
Output
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,</code></pre>However, the <code>limit()</code> function only allows to limit the the number of element, whereas the new <code>iterate()</code> the predicate can be anything. For example, in the following example when we change the increment by 2 instead of 1, the <code>limit()</code> will print upto 18, whereas the new <code>iterate()</code> function will print only till 8.<pre><code>Stream<Integer> stream3 = Stream.iterate(0, n -> n + 2).limit(10);
stream3.forEach(x -> System.out.print(x + ", "));
System.out.println();
Stream<Integer> stream4 = Stream.iterate(0, n -> n < 10, n -> n + 2);
stream4.forEach(x -> System.out.print(x + ", "));
System.out.println();
Output
0, 2, 4, 6, 8, 10, 12, 14, 16, 18,
0, 2, 4, 6, 8, </code></pre>
<h3>ofNullable Method</h3>
The Java 9 ofNullable() can be used to generate a stream consisting of a single element. From the Javadoc<blockquote>Returns a sequential Stream containing a single element, if non-null, otherwise returns an empty Stream.</blockquote>The following code will create a stream consisting of exactly one element (1).<pre><code>Stream<Integer> ofNullable1 = Stream.ofNullable(1);
ofNullable1.forEach(System.out::println);
Output
1</code></pre>The following code returns an empty stream (not null, but an empty stream)<pre><code>Stream<Integer> ofNullable2 = Stream.ofNullable(null);
ofNullable2.forEach(System.out::println);
Output
</code></pre>abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com0tag:blogger.com,1999:blog-18313336.post-87634078676371768302017-09-27T07:15:00.000-04:002017-09-27T07:15:45.321-04:00Java 9 Streams : takeWhile() methodIn Java 9, comes with a few good additions to the Stream API. For more information on the Java 8 Streams, go to the Java 8 Page. The following new methods were added to the Java 9 Stream API.<ol><li>takeWhile</li><li>dropWhile</li><li>iterate</li><li>ofNullable</li></ol>
In this post we will take a look at the takeWhile() method.<a name='more'></a>
<h3>takeWhile() method</h3>
In Stream API, <code>takeWhile()</code> Method takes a Predicate(function returning true or false) as an argument, and returns the set of elements of the stream that match the Predicate. However, this behavior varies between ordered and unordered streams. <pre><code>Stream<T> takeWhile(Predicate<? super T> predicate)</code></pre>In all the examples below, We will use the following list as a starting point, unless mentioned otherwise.
<pre><code>List<String> list = List.of("returns", "if", "this", "stream", "is", "ordered,", "stream", "consisting", "of", "the",
"longest", "prefix", "of", "elements", "taken", "from", "this", "stream", "that", "match", "the", "given",
"predicate");</code></pre>
As you can see, the sorted version of the list will look like this<pre><code>consisting, elements, from, given, if, is, longest, match, of, of, ordered,, predicate, prefix, returns, stream, stream, stream, taken, that, the, the, this, this</code></pre>
<h3>For Ordered Stream</h3>
From the Javadoc<blockquote>If this stream is ordered then the longest prefix is a contiguous sequence of elements of this stream that match the given predicate. The first element of the sequence is the first element of this stream, and the element immediately following the last element of the sequence does not match the given predicate.</blockquote>
This effectively means that if for an ordered list, takeWhile() will return a value only if the first element in this stream matches the predicate. If the first element doesn't match the predicate, we get back empty stream. You can see this behavior in the following example where we Predicate is to check if the length of a string is less than 4. Since the first element of the sorted stream "consists" is longer than 4 characters, we get back an empty stream.<pre><code> list
.stream()
.sorted()
.takeWhile(x -> x.length() < 4)
.forEach(System.out::println);</code></pre>
However, if the first element of the stream matches the predicate, then we will get the first few elements of the Stream that match the predicate. As soon as the predicate returns false, takeWhile() stops, even if there are any subsequent elements that match the predicate further downstream. In the following example, we check for strings length greater than 2, which will return "consisting, elements, from, given", and stops before "if".<pre><code>list
.stream()
.sorted()
.takeWhile(x -> x.length() > 2)
.forEach(System.out::println);
Output:
consisting
elements
from
given </code></pre>
Another example<pre><code>list
.stream()
.sorted()
.takeWhile(x -> x.contains("c"))
.forEach(System.out::println);
Output:
consisting</code></pre>
<h3>For Unordered Stream</h3>
From the Javadoc<blockquote>If this stream is unordered, and some (but not all) elements of this stream match the given predicate, then the behavior of this operation is nondeterministic; it is free to take any subset of matching elements (which includes the empty set).</blockquote>
<pre><code>list
.stream()
.takeWhile(x -> x.contains("t"))
.forEach(System.out::println);
Output:
returns</code></pre>The following Stream of number where we check for number less than 7,<pre><code>Stream.of(1,5,3,2,4,9,7)
.takeWhile(x->x <7)
.forEach(System.out::println);
Output:
1
5
3
2
4</code></pre>
Finally, Here is the full code<pre><code>package com.aoj.java9.collections;
import java.util.List;
import java.util.stream.Stream;
public class Java9StreamsTakeWhile {
public static void main(String[] args) {
List<String> list = List.of("returns", "if", "this", "stream", "is", "ordered,", "stream", "consisting", "of", "the",
"longest", "prefix", "of", "elements", "taken", "from", "this", "stream", "that", "match", "the", "given",
"predicate");
list.stream().sorted().forEach(System.out::println);
list
.stream()
.sorted()
.takeWhile(x -> x.length() > 2)
.forEach(System.out::println);
list
.stream()
.sorted()
.takeWhile(x -> x.contains("c"))
.forEach(System.out::println);
list
.stream()
.sorted()
.takeWhile(x -> x.length() < 4)
.forEach(System.out::println);
list
.stream()
.takeWhile(x -> x.contains("t"))
.forEach(System.out::println);
Stream.of(1,5,3,2,4,9,7)
.takeWhile(x->x <7)
.forEach(System.out::println);
}
}</code></pre>abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com0tag:blogger.com,1999:blog-18313336.post-5721196684145134712017-09-26T07:26:00.000-04:002017-09-26T07:28:27.706-04:00Java 9: Factory Methods to initialize Immutable CollectionsJava 9 introduces convenient factory methods to create immutable List, Map, and Set collections. In this post, I will show how to use the new factory methods to <ul><li><a href="#ImmutableList">Initialize immutable List with Java 9</a></li><li><a href="#ImmutableSet">Initialize immutable Set with Java 9</a></li><li><a href="#ImmutableMap">Immutable Map with Java 9</a></li></ul>
<a name='more'></a>
<h3>Java 8 Immutable Collections</h3>
Prior to Java 9, to create immutable collections, you would something like below<pre><code>List<String> list8 = new ArrayList<String>();
list8.add("YHOO");
list8.add("AAPL");
list8.add("GOOG");
list8.add("MSFT");
List<String> immutableList8 = Collections.unmodifiableList(list8);
//immutableList8.add("ORCL");// Will throw java.lang.UnsupportedOperationException
immutableList8.forEach(System.out::println);</code></pre>This example shows only an implementation for List (Although Arrays.asList(..) would have done as well), and Set and Map would look something similar too.
<h3>Initialize Immutable List in Java 9</h3><a name="ImmutableList" ></a>
In Java 9, <code>java.util.List</code> provides multiple methods to initialize immutable lists, shown below<pre><code>static <E> List<E> of(E e1)
static <E> List<E> of(E e1,E e2)
static <E> List<E> of(E e1,E e2,E e3)
static <E> List<E> of(E e1,E e2,E e3,E e4)
static <E> List<E> of(E e1,E e2,E e3,E e4,E e5)
static <E> List<E> of(E e1,E e2,E e3,E e4,E e5,E e6)
static <E> List<E> of(E e1,E e2,E e3,E e4,E e5,E e6,E e7)
static <E> List<E> of(E e1,E e2,E e3,E e4,E e5,E e6,E e7,E e8)
static <E> List<E> of(E e1,E e2,E e3,E e4,E e5,E e6,E e7,E e8,E e9)
static <E> List<E> of(E e1,E e2,E e3,E e4,E e5,E e6,E e7,E e8,E e9,E e10)
static <E> List<E> of(E... elements) // Var-args variation</code></pre>Following is an example of how to use this to create a List<String><pre><code>List<String> immutableList = List.of("YHOO", "AAPL", "GOOG", "MSFT");
// immutableList.add("ORCL"); // Will throw java.lang.UnsupportedOperationException
immutableList.for/ESystem.out::println);</code></pre>
<h3>Initialize Immutable Set in Java 9</h3><a name="ImmutableSet" ></a>
Similar to List, you have the same type of methods for <code>java.util.Set</code><pre><code>static <E> Set<E> of(E e1)
static <E> Set<E> of(E e1,E e2)
static <E> Set<E> of(E e1,E e2,E e3)
static <E> Set<E> of(E e1,E e2,E e3,E e4)
static <E> Set<E> of(E e1,E e2,E e3,E e4,E e5)
static <E> Set<E> of(E e1,E e2,E e3,E e4,E e5,E e6)
static <E> Set<E> of(E e1,E e2,E e3,E e4,E e5,E e6,E e7)
static <E> Set<E> of(E e1,E e2,E e3,E e4,E e5,E e6,E e7,E e8)
static <E> Set<E> of(E e1,E e2,E e3,E e4,E e5,E e6,E e7,E e8,E e9)
static <E> Set<E> of(E e1,E e2,E e3,E e4,E e5,E e6,E e7,E e8,E e9,E e10)
static <E> Set<E> of(E... elements) // Var-args variation</code></pre>Following example demonstrates how to use this to create a Set<String><pre><code>Set<String> immutableSet = Set.of("YHOO", "AAPL", "GOOG", "MSystem.out::println);</code></pre>
<h3>Initialize Immutable Map in Java 9</h3><a name="ImmutableMap" ></a>
When it comes to <code>java.util.Map</code> the simple methods support upto 10 <code><key,value></code> pairs. <pre><code>static <K,V> Map<K,V> of(K k1, V v1)
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2)
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3)
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3)
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4)
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5)
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6)
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7)
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8)
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9)
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10)</code></pre>Here is a simple way to initialize an Immutable Map<pre><code>Map<String, String> immutableMap = Map.of("YHOO", "Yahoo", "AAPL", "Apple", "GOOG", "Alphabet", "MSFT", "Microsoft");
immutableMap.forEach((key, value) -> System.out.println(key + " : " + value));</code></pre>Beyond that the var-args, that variation takes a variable number of arguments of "java.util.Map.entry"<pre><code>static <K,V> Map<K,V> ofEntries(Map.Entry<? extends K,? extends V>... entries)</code></pre>Here is an example of how to use the varags variation to initialize an immutable Map<pre><code>Map<String, String> immutableMap2 = Map.ofEntries(Map.entry("YHOO", "Yahoo"), Map.entry("AAPL", "Apple"), Map.entry("GOOG", "Alphabet"), Map.entry("MSFT", "Microsoft"));
immutableMap2.forEach((key, value) -> System.out.println(key + " : " + value));</code></pre>
<h3>The Full Code to directly run these examples</h3><pre><code>package com.aoj.java9.collections;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Immutables {
public static void main(String[] args) {
List<String> list8 = new ArrayList<String>();
list8.add("YHOO");
list8.add("AAPL");
list8.add("GOOG");
list8.add("MSFT");
List<String> immutableList8 = Collections.unmodifiableList(list8);
//immutableList8.add("ORCL");// Will throw java.lang.UnsupportedOperationException
immutableList8.forEach(System.out::println);
List<String> immutableList = List.of("YHOO", "AAPL", "GOOG", "MSFT");
// immutableList.add("ORCL"); // Will throw java.lang.UnsupportedOperationException
immutableList.forEach(System.out::println);
Map<String, String> immutableMap = Map.of("YHOO", "Yahoo", "AAPL", "Apple", "GOOG", "Alphabet", "MSFT", "Microsoft");
immutableMap.forEach((key, value) -> System.out.println(key + " : " + value));
Map<String, String> immutableMap2 = Map.ofEntries(Map.entry("YHOO", "Yahoo"), Map.entry("AAPL", "Apple"), Map.entry("GOOG", "Alphabet"), Map.entry("MSFT", "Microsoft"));
immutableMap2.forEach((key, value) -> System.out.println(key + " : " + value));
Set<String> immutableSet = Set.of("YHOO", "AAPL", "GOOG", "MSFT");
immutableSet.forEach(System.out::println);
}
}</code></pre>abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com0tag:blogger.com,1999:blog-18313336.post-74108028336396356852017-09-25T23:33:00.000-04:002017-09-25T23:33:56.622-04:00Setup Java 9 in Eclipse OxygenThis post gives the quick steps to setup Eclipse Oxygen with Java 9. This relies on Java™ 9 support for Eclipse JDT is available now. At this time, the it is not fully functional, and I have faced a couple of issues setting this up. Full support for Java 9 is expected on October 11, 2017 with Oxygen 1a release. Follow these steps to install the support for Java 9.<a name='more'></a><ol><li>Download and Install Java 9 available at <a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">Oracle Java SE Download page</a>. On Windows machines, it will automatically update your path to use Java 9. Once you install, open a command line window and run "java -version" to verify. It should like below<pre><code>C:\>java -version
java version "9"
Java(TM) SE Runtime Environment (build 9+181)
Java HotSpot(TM) 64-Bit Server VM (build 9+181, mixed mode)</code></pre></li><li>Go to the Eclipse Marketplace and search for "Java 9". You should be able to see "Java 9 Support for Oxygen 4.7".<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiW7i9mqdywR7wIaKrjcI1qNYVox0vZRwqJOEZ0rPPxXPqSsaJphiE3Cj0x226pOhLPzS75bkLmyGJnFo5332b0CZvXMdRZuh3hI-TPtmVhvucbWbqhLUzwkBIeAYqZ4vZm8dKg4Q/s1600/Java+9+Setup+1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiW7i9mqdywR7wIaKrjcI1qNYVox0vZRwqJOEZ0rPPxXPqSsaJphiE3Cj0x226pOhLPzS75bkLmyGJnFo5332b0CZvXMdRZuh3hI-TPtmVhvucbWbqhLUzwkBIeAYqZ4vZm8dKg4Q/s1600/Java+9+Setup+1.png" data-original-width="518" data-original-height="740" /></a></div></li><li>Click Install. You can ignore "Eclipse CVS Client", "Eclipse Project SDK", and "org.eclipse.sdk.ide" options and click confirm.</li><li>Select "Update my installation to be compatible with the items being installed", if you see the second confirm dialog as shown below. And click Confirm.<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN0tjwvBLSwE9UWekiJtM2WIuYbqzXuVjrPH3lHFd8qbk5mJUPyCjO4Odztd2TGMFrFVqbrlUdel7Y2ZFXe4S12GKY6JeqUL4-SLBxANKAvCipHGDelLqsWi8fays6QASFdqXcUQ/s1600/Java+9+Setup+3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN0tjwvBLSwE9UWekiJtM2WIuYbqzXuVjrPH3lHFd8qbk5mJUPyCjO4Odztd2TGMFrFVqbrlUdel7Y2ZFXe4S12GKY6JeqUL4-SLBxANKAvCipHGDelLqsWi8fays6QASFdqXcUQ/s1600/Java+9+Setup+3.png" data-original-width="602" data-original-height="740" /></a></div></li><li>Agree to the term and click finish.<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgflhXoEySPNBWO8ueu6BN6z_nqtThlPArskRQJWfn01J6zrf9xc-9BE14u5XMiEshKflzzwQFz7L82BM0KFMiaEI0Mee_h0zXSDODPzkzsRGQ40f12GvnUloggAr2XvNq0VTGw0A/s1600/Java+9+Setup+4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgflhXoEySPNBWO8ueu6BN6z_nqtThlPArskRQJWfn01J6zrf9xc-9BE14u5XMiEshKflzzwQFz7L82BM0KFMiaEI0Mee_h0zXSDODPzkzsRGQ40f12GvnUloggAr2XvNq0VTGw0A/s1600/Java+9+Setup+4.png" data-original-width="602" data-original-height="740" /></a></div></li><li>Once eclipse restarts, you should be able to see jre-9 in "Installed JREs". To see this go to Window->Preferences->Java->Installed JREs.<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqzhAqxvvX0OejLLkQ3IfnWjfgRhndhSkxMzfB5wTLdti5v9nErOpQrJHxg6cyg7aDYXZNlRLFy10MPZgNIhR9TjYL55W4pbJbyIEA-UDIdBZEqwXVgTK5YuTcAiiTLSj2-xyg4w/s1600/Java+9+Setup+5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqzhAqxvvX0OejLLkQ3IfnWjfgRhndhSkxMzfB5wTLdti5v9nErOpQrJHxg6cyg7aDYXZNlRLFy10MPZgNIhR9TjYL55W4pbJbyIEA-UDIdBZEqwXVgTK5YuTcAiiTLSj2-xyg4w/s1600/Java+9+Setup+5.png" data-original-width="687" data-original-height="537" /></a></div></li><li>Once this is setup, you should be able to run Java 9 projects like any other project.</li></ol>abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com0tag:blogger.com,1999:blog-18313336.post-32652298519808071532017-09-24T13:30:00.000-04:002017-09-26T10:50:32.700-04:00Using Comparators with Java 8 StreamsThis post gives a few examples of how to use Comparator with Java 8 streams to Sort and to find the Maximum and Minimum elements in a stream.
<h3>Comparing Simple types with Comparator.comparing* methods</h3>The <code>Comparator.comparingDouble</code>, <code>Comparator.comparingInt</code> and <code>Comparator.comparingLong</code> etc. methods can be used to do sorting or finding max and min from stream. The following example uses the comparingDouble method to compare and sort a stream of doubles generated using the <code>Stream.generate()</code> method. The Stream.generate has been explained my earlier post "<a href="/2017/08/java-8-streams.html">Java 8 Streams</a>" <pre><code> // Sort a stream of Doubles
Stream.generate(Math::random).limit(10).sorted(Comparator.comparingDouble(Double::valueOf)).forEach(System.out::println);</code></pre>
<a name='more'></a>
<h3>Comparator.comparing method</h3>
The <code>Comparator.comparing</code> method gives a more flexible implementation which can be used to compare Objects of any type. There are a couple of variations of this method which we will see in the following examples.
<h3>Comparator.comparing method to compare Double</h3>
In the following example, we collect a stream of doubles generated using the <code>Stream.generate</code> method and print the numbers followed by using the <code>Comparator.comparing</code> method.<pre><code> // Max from a list of Doubles
List<Double> doubles = Stream.generate(Math::random).limit(10).collect(Collectors.toList());
doubles.stream().forEach(System.out::println);
System.out
.println("Max from random number : " + doubles.stream().max(Comparator.comparing(Function.identity())).get());</code></pre>
<h3>Comparator.comparing method to compare Dates</h3>
In the following example, we use the <code>Comparator.comparing</code> method to compare a list of <code>LocalDate</code> objects. <pre><code> // Max and min from a stream of dates
LocalDate start = LocalDate.now();
List<LocalDate> dates = Stream.iterate(start, date -> date.plusDays(1)).limit(100).collect(Collectors.toList());</code></pre>
<h3>Using Comparators on Streams with User Defined Classes</h3>
For the following few examples, we will use the Country Class defined below, and corresponding list shown below. The Country class consists of the name, Captial city and GDP (in trillions) of the country. I have changed a couple of values which are close enough to be equal in order to demonstrate a few variations of the <code>Comparator.comparable</code> method. This class also defines a natural ordering on the GDP by implementing the Comparable interface.<pre><code>package beans;
public class Country implements Comparable<Country> {
public String name;
public String capital;
public Double gdp;
public Country(String name, String capital, Double gdp) {
this.name = name;
this.capital = capital;
this.gdp = gdp;
}
@Override
public int compareTo(Country o) {
return gdp.compareTo(o.getGdp());
}
// ... Getters Setters and toString</code></pre><pre><code> List<Country> countries = new ArrayList<Country>();
countries.add(new Country("United States", "Washington DC", 18.56));
countries.add(new Country("China", "Beijing", 11.21));
countries.add(new Country("Japan", "Tokyo", 4.93));
countries.add(new Country("Germany", "Berlin", 3.46));
countries.add(new Country("United Kingdom", "London", 2.62));
countries.add(new Country("France", "Paris", 2.46));
countries.add(new Country("India", "New Delhi", 2.46));
countries.add(new Country("Italy", "Rome", 1.85));
countries.add(new Country("Brazil", "Brasília", 1.85));</code></pre>
<h3>Comparator.comparing with Natural Ordering</h3>
In the first variation, the comparing method takes a Function which returns a Comparable as a parameter. Since our Country class implements the Comparable method, we will use the <code>Function.identity()</code> method to return the Country object. The Function.identity method behaves similar to the lambda <code>x->x</code>. In the following piece of code, we use the comparing method to print the country with the max and min GDP from the list<pre><code> // Countries with Max and Min GDPs from a list of countries
Comparator<Country> compareNatural = Comparator.comparing(Function.identity());
Country maxGdp = countries.stream().max(compareNatural).get();
Country minGdp = countries.stream().min(compareNatural).get();
System.out.println("Country with Max GDP in the list : " + maxGdp.getName());
System.out.println("Country with Min GDP in the list : " + minGdp.getName());</code></pre>
<h3>Comparator.comparing using specific fields in the class</h3>
In the following few examples, we use the comparing method to sort the list of countries using different fields. Since all the fields in the Country class are comparable, we can use the get methods to return Comparable objects as shown below.<pre><code> // Sort Countries by Capital
Comparator<Country> compareCapital = Comparator.comparing(Country::getCapital);
countries.stream().sorted(compareCapital)
.forEach(x -> System.out.println(x.getName() + " : " + x.getCapital()));
// Sort Countries by Name
Comparator<Country> compareName = Comparator.comparing(Country::getName);
countries.stream().sorted(compareName).forEach(x -> System.out.println(x.getName()));
// Sort by GDP
Comparator<Country> compareGdp = Comparator.comparing(Country::getGdp);
countries.stream().sorted(compareGdp)
.forEach(x -> System.out.println(x.getName() + " : " + x.getGdp()));</code></pre>
<h3>Using Comparator.comparing method with custom comparators</h3>
The <code>Comparator.comparing</code> method has a variation that takes in a custom Comparator as an additional parameter to override the natural ordering. In the following example, we use the custom comparator to see if the Countries have equal GDP, in which case we will go to the second ordering which is by the Country name. <pre><code> // Compare with custom comparator different from natural ordering
Comparator<? super Country> customComparator = (c1, c2) -> {
return (c1.compareTo(c2) != 0)
? c1.compareTo(c2) // Compare by natural ordering if not equal
: ((Country) c2).getName().compareTo(((Country) c1).getName()); // Compare reverse by name if equal by natural ordering
};
countries.stream().sorted(Comparator.comparing(Function.identity(), customComparator)).forEach(System.out::println);</code></pre>
<h3>The thenComparing method</h3>
The thenComparing method allows using multiple sort keys on the stream. The functionality is similar to the above example where we manually compare the fields one after the other.<pre><code> // Compare and then
Comparator<Country> thenComparing = Comparator
.comparing(Country::getGdp)
.thenComparing(Country::getName);
countries.stream()
.sorted(thenComparing)
.forEach(System.out::println);</code></pre><h3>Here is the full code</h3><h3>streams.StreamsComparator</h3><pre><code>package streams;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import beans.Country;
public class StreamsComparator {
public static void main(String[] args) {
// Sort a stream of Doubles
Stream.generate(Math::random).limit(10).sorted(Comparator.comparingDouble(Double::valueOf)).forEach(System.out::println);
// Max from a list of Doubles
List<Double> doubles = Stream.generate(Math::random).limit(10).collect(Collectors.toList());
doubles.stream().forEach(System.out::println);
System.out
.println("Max from random number : " + doubles.stream().max(Comparator.comparing(Function.identity())).get());
// Max and min from a stream of dates
LocalDate start = LocalDate.now();
List<LocalDate> dates = Stream.iterate(start, date -> date.plusDays(1)).limit(100).collect(Collectors.toList());
LocalDate maxDate = dates.stream().max(Comparator.comparing(Function.identity())).get();
LocalDate minDate = dates.stream().min(Comparator.comparing(Function.identity())).get();
System.out.println("Last Date = " + maxDate);
System.out.println("First Date = " + minDate);
List<Country> countries = new ArrayList<Country>();
countries.add(new Country("United States", "Washington DC", 18.56));
countries.add(new Country("China", "Beijing", 11.21));
countries.add(new Country("Japan", "Tokyo", 4.93));
countries.add(new Country("Germany", "Berlin", 3.46));
countries.add(new Country("United Kingdom", "London", 2.62));
countries.add(new Country("France", "Paris", 2.46));
countries.add(new Country("India", "New Delhi", 2.46));
countries.add(new Country("Italy", "Rome", 1.85));
countries.add(new Country("Brazil", "Brasília", 1.85));
// Countries with Max and Min GDPs from a list of countries
Comparator<Country> compareNatural = Comparator.comparing(Function.identity());
Country maxGdp = countries.stream().max(compareNatural).get();
Country minGdp = countries.stream().min(compareNatural).get();
System.out.println("Country with Max GDP in the list : " + maxGdp.getName());
System.out.println("Country with Min GDP in the list : " + minGdp.getName());
// Sort Countries by Capital
Comparator<Country> compareCapital = Comparator.comparing(Country::getCapital);
countries.stream().sorted(compareCapital)
.forEach(x -> System.out.println(x.getName() + " : " + x.getCapital()));
// Sort Countries by Name
Comparator<Country> compareName = Comparator.comparing(Country::getName);
countries.stream().sorted(compareName).forEach(x -> System.out.println(x.getName()));
// Sort by GDP
Comparator<Country> compareGdp = Comparator.comparing(Country::getGdp);
countries.stream().sorted(compareGdp)
.forEach(x -> System.out.println(x.getName() + " : " + x.getGdp()));
// Compare with custom comparator different from natural ordering
Comparator<? super Country> customComparator = (c1, c2) -> {
return (c1.compareTo(c2) != 0)
? c1.compareTo(c2) // Compare by natural ordering if not equal
: ((Country) c2).getName().compareTo(((Country) c1).getName()); // Compare reverse by name if equal by natural ordering
};
countries.stream().sorted(Comparator.comparing(Function.identity(), customComparator)).forEach(System.out::println);;
// Compare and then
Comparator<Country> thenComparing = Comparator
.comparing(Country::getGdp)
.thenComparing(Country::getName);
countries.stream()
.sorted(thenComparing)
.forEach(System.out::println);
}
}</code></pre><h3>beans.Country</h3><pre><code>package beans;
public class Country implements Comparable<Country> {
public String name;
public String capital;
public Double gdp;
public Country(String name, String capital, Double gdp) {
this.name = name;
this.capital = capital;
this.gdp = gdp;
}
@Override
public int compareTo(Country o) {
return gdp.compareTo(o.getGdp());
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCapital() {
return capital;
}
public void setCapital(String capital) {
this.capital = capital;
}
public Double getGdp() {
return gdp;
}
public void setGdp(Double gdp) {
this.gdp = gdp;
}
@Override
public String toString() {
return "Country [name=" + name + ", capital=" + capital + ", gdp=" + gdp + "]";
}
}</code></pre>abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com0tag:blogger.com,1999:blog-18313336.post-3260488955527938052017-09-18T23:23:00.000-04:002017-09-18T23:23:53.984-04:00Auto-Restart Spring Boot Application On Code Change With Dev ToolsSpring Boot Dev Tools enables auto-restarting a Spring boot application whenever any class is changed in the class path. This is not comparable in speed with the hot swap functionality offered by Jrebel or Spring Loaded, but this is a very simple and easy way to implement and better than manual restart. In this post, I use a simple Spring boot rest echo service to demonstrate how spring boot dev tools can be used to auto restart the application when using Maven on an IDE or Gradle from command line. In either options, the main trigger for a restart is the change to a class file, which means that the change to a Java file has to be compiled either by the IDE in option 1 or by Gradle in option 2.<a name='more'></a>
The only thing that you have to do from the application is to add a dependency to spring boot dev tools
<h3>Maven</h3><pre><dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency></pre><h3>Gradle</h3><pre>runtime('org.springframework.boot:spring-boot-devtools')</pre>
For this example, I am using a simple Spring Boot application created by <a href="https://start.spring.io/">Spring Initializr</a>, and add the following Java class as a simple echo service<pre>package com.aoj.springdevtools;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class EchoService {
@RequestMapping("/echo")
public String greeting(@RequestParam(value = "name") String name) {
return "Hello1 : " + name;
}
}</pre>
<h3>With Maven and Eclipse</h3>
Once you get the project from Spring Initializr, import it as a Maven project. And add the Java class to the source. From eclipse, use "Run as Java application" to run the Spring boot application, and it will start the application. Any code changes you made will be automatically compiled by Eclpise and Spring boot will restart the appliation automatically.
<h3>With Gradle</h3>
Gradle provides a continuous build option, which keep track of the source folders and triggers a build whenever the source is changed. The automatic build by Gradle, in turn, trigger the restart of the Spring boot application. To see this in action you will need two command-line windows. <ol><li>In the first window start the gradle continuous build with the following command<pre>gradlew build --continuous</pre></li><li>In the second window, run the spring boot application with the command<pre>gradle bootRun</pre></li></ol>Once you are done with these steps, if you change your source file, you will notice that a build is triggered in the first window, following which, a restart of spring boot application can be seen in the second window.
Here is the source code for the project
<h3>build.gradle</h3><pre>buildscript {
ext {
springBootVersion = '2.0.0.M4'
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" }
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'com.aoj'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" }
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-web')
runtime('org.springframework.boot:spring-boot-devtools')
testCompile('org.springframework.boot:spring-boot-starter-test')
}</pre><h3>pom.xml</h3><pre><?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.aoj</groupId>
<artifactId>spring-devtools</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-devtools</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.M4</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<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-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project></pre><h3>SpringDevtoolsApplication.java</h3><pre>package com.aoj.springdevtools;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringDevtoolsApplication {
public static void main(String[] args) {
SpringApplication.run(SpringDevtoolsApplication.class, args);
}
}</pre><h3>EchoService.java</h3><pre>package com.aoj.springdevtools;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class EchoService {
@RequestMapping("/echo")
public String greeting(@RequestParam(value = "name") String name) {
return "Hello1 : " + name;
}
}</pre>abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com0tag:blogger.com,1999:blog-18313336.post-53871649112150909962017-09-11T10:29:00.000-04:002017-09-11T10:29:34.819-04:00Passing System Properties and Arguments With GradleWhen using the Gradle application plugin, Gradle spawns a new JVM on the fly, and does not pass the System Properties or Command-line arguments to the new Java process. This post explains how to pass the System properties and command-line arguments when using Gradle application plugin.
<a name='more'></a>
There are multiple ways to pass the System properties or arguments to the Application<h3>Pass all System properties</h3><pre><code>systemProperties System.getProperties()</code></pre><h3>Pass specific system property</h3><pre><code>systemProperty "prop1", System.getProperty("prop1")</code></pre><h3>Pass a subset of System Properties</h3>In the following example, we only pass system properties that start with "a".<pre><code>System.properties.each { key,value->
if (key.startsWith("a")) {
systemProperty key, value
}
}</code></pre><h3>Pass command line arguments</h3> For this you can read the arguments as a Gradle System property and pass on the application in using "args" as shown below.<pre><code>args System.getProperty("exec.args")</code></pre><h3>Full Code</h3><h3>Folder Structure</h3><pre><code>GradleSysPropsExample
│ build.gradle
└───src
├───main
│ └───java
│ └───com
│ └───aoj
│ GradleSysPropsExample.java
│
└───test
└───java</code></pre><h3>GradleSysProperExample.java</h3><pre><code>package com.aoj;
public class GradleSysPropsExample {
public static void main(String[] args) {
//System.getProperties().forEach((key, value) -> System.out.println(key + " : " + value));
//System.out.println("System Property prop1 = " + System.getProperty("prop1"));
System.out.println("System Property aoj-cmd-args = " + System.getProperty("aoj-cmd-args"));
System.out.println("Command line arguments");
for(String arg: args) {
System.out.println(arg);
}
}
}</code></pre><h3>build.gradle</h3><pre><code>apply plugin:'application'
mainClassName = "com.aoj.GradleSysPropsExample"
applicationName = 'GracleSysPropsExample'
repositories {
mavenCentral()
}
dependencies {
}
run {
// Pass all system properties
// systemProperties System.getProperties()
// Pass specific system property
systemProperty "prop1", System.getProperty("prop1")
// Pass argument starting with "a"
System.properties.each { key,value->
if (key.startsWith("a")) {
systemProperty key, value
}
}
// Pass command line arguments
args System.getProperty("aoj-cmd-args").split(',')
}</code></pre><h3>To run this example</h3><pre><code>gradle run -Dprop1=prop1value -Daoj-cmd-args="arg1,arg2"</code></pre>abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com2tag:blogger.com,1999:blog-18313336.post-61460144552097747742017-09-10T01:07:00.001-04:002017-09-10T01:07:25.184-04:00Load Environment Specific Properties Files Using SpringOne of the more common aspects of enterprise application development involves environment specific properties files. Some examples include Database configurations or external JMS resources etc. The common way to address this problem is to use multiple properties file an build the Application EAR/WAR/JAR at compile time. Although this works, this solution also means that we maintain different build scripts for different environments, or having some file renames etc. while building the application. Spring profiles address this problem in a more efficient way. Like any other property, using Spring profiles, we can inject the environment profile into Spring and Spring will handle the loading of the appropriate configuration files. In this post, I show how to load environment specific properties files using Spring.
<a name='more'></a>
This example shows a simple application that has three environments dev,qa, and prod. Each environment has it's own properties files and we expect to print the properties based on the environment property passed from command line. Here are the important steps<ul><li>Define profiles in Spring context file<pre><code><beans profile="dev">
<context:property-placeholder
location="classpath:config-default.properties, classpath:config-dev.properties"
ignore-unresolvable="true" />
</beans></code></pre></li><li>Inject the environment variables using <code>${}</code> into the required classes.<pre><code>@Value("${app.name}")
private String appName;</code></pre></li><li>Pass the profile information from command line, or update environment in code.<pre><code>gradle run -Dspring.profiles.active=prod</code></pre><pre><code>ConfigurableEnvironment env = (ConfigurableEnvironment) context.getEnvironment();
env.setActiveProfiles("qa");
((AbstractApplicationContext) context).refresh();</code></pre></li></ul> Here is the full code
<h3>Directory Structure</h3><pre><code>SpringEnvProperties
└───src
├───main
│ ├───java
│ │ └───com
│ │ └───aoj
│ │ │ SpringEnvProperties.java
│ │ │
│ │ └───service
│ │ DependsOnEnv.java
│ │
│ └───resources
│ applicationContext.xml
│ config-default.properties
│ config-dev.properties
│ config-prod.properties
│ config-qa.properties
│
└───test
└───java</code></pre>
<h3>applicationContext.xml</h3><pre><code><?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.aoj.service" />
<beans profile="dev">
<context:property-placeholder
location="classpath:config-default.properties, classpath:config-dev.properties"
ignore-unresolvable="true" />
</beans>
<beans profile="qa">
<context:property-placeholder
location="classpath:config-default.properties, classpath:config-qa.properties"
ignore-unresolvable="true" />
</beans>
<beans profile="prod">
<context:property-placeholder
location="classpath:config-default.properties, classpath:config-prod.properties"
ignore-unresolvable="true" />
</beans>
</beans></code></pre><h3>config-default.properties</h3><pre><code>app.name=SpringEnvProperties</code></pre><h3>config-dev.properties</h3><pre><code>env.name=dev
env.prop1=propDev</code></pre><h3>config-qa.properties</h3><pre><code>env.name=qa
env.prop1=propQA</code></pre><h3>config-prod.properties</h3><pre><code>env.name=prod
env.prop1=propProduction</code></pre><h3>SpringEnvProperties.java</h3><pre><code>package com.aoj;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import com.aoj.service.DependsOnEnv;
public class SpringEnvProperties {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:/applicationContext.xml");
System.out.println("Properties : " + System.getProperty("spring.profiles.active"));
DependsOnEnv test = context.getBean(DependsOnEnv.class);
test.printEnv();
// Update environment from code.
ConfigurableEnvironment env = (ConfigurableEnvironment) context.getEnvironment();
env.setActiveProfiles("qa");
((AbstractApplicationContext) context).refresh();
test = context.getBean(DependsOnEnv.class);
test.printEnv();
}
}</code></pre><h3>DependsOnEnv.java</h3><pre><code>package com.aoj.service;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class DependsOnEnv {
@Value("${app.name}")
private String appName;
@Value("${env.name}")
private String envName;
@Value("${env.prop1}")
private String envProp1;
public void printEnv() {
System.out.println("App Name : " + appName);
System.out.println("Current Env : " + envName);
System.out.println("Current Env Prop : " + envProp1);
}
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName = appName;
}
public String getEnvName() {
return envName;
}
public void setEnvName(String envName) {
this.envName = envName;
}
public String getEnvProp1() {
return envProp1;
}
public void setEnvProp1(String envProp1) {
this.envProp1 = envProp1;
}
}</code></pre><h3>build.gradle</h3><pre><code>apply plugin:'application'
mainClassName = "com.aoj.SpringEnvProperties"
applicationName = 'SpringEnvProperties'
repositories {
mavenCentral()
}
dependencies {
compile group: 'org.springframework', name: 'spring-core', version: '4.3.9.RELEASE'
compile group: 'org.springframework', name: 'spring-context', version: '4.3.9.RELEASE'
compile group: 'org.springframework', name: 'spring-beans', version: '4.3.9.RELEASE'
compile group: 'org.springframework', name: 'spring-tx', version: '4.3.9.RELEASE'
compile group: 'org.springframework', name: 'spring-orm', version: '4.3.9.RELEASE'
// Use JUnit test framework
compile 'junit:junit:4.12'
}
// Required to pass gradle command-line system properties to the Java process
run {
systemProperty "spring.profiles.active", System.getProperty("spring.profiles.active")
}</code></pre><h3>Caution for Gradle users</h3>While using gradle, if you do not pass the System properties using "systemProperty" as shown in the <code>build.gradle</code> file above, you will see that the properties will not be passed to the java program, and you might see something like below<pre><code>INFO: Skipped XML bean definition file due to specified profiles [prod] not matching: class path resource [applicationContext.xml]
Properties : null
App Name : ${app.name}
Current Env : ${env.name}
Current Env Prop : ${env.prop1}</code></pre>You can see that instead of the environment properties, it will just print the <code>${}</code>.abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com0tag:blogger.com,1999:blog-18313336.post-74378252170974065752017-09-07T08:40:00.001-04:002017-09-07T08:40:38.391-04:00Merge and Paginate PDF files using iText 5In this post we will see a way to merge multiple PDF files while adding page numbers at the bottom of each page in the format <i>Page 1 of 10</i>. The following steps give a brief description of the steps used to merge and add page number to the merged PDF.
<a name='more'></a>
<ol><li>Create <code>com.itextpdf.text.pdf.PdfReader</code> from all InputStreams and retrieve the page counts to get a total page count. We also add the readers to an ArrayList to use later.<pre><code>List<PdfReader> readers = new ArrayList<PdfReader>();
int totalPageCount = 0;
for (InputStream file : streamOfPDFFiles) {
// Create Reader for each input stream and add to reader list
PdfReader reader = new PdfReader(file);
readers.add(reader);
totalPageCount += reader.getNumberOfPages();
}</code></pre></li><li>Create a PageStamp for each page. <code>com.itextpdf.text.pdf.PdfCopy.PageStamp</code> can be used to add content to pages in the merged PDF.<pre><code>PdfImportedPage page = copy.getImportedPage(reader, i);
PageStamp stamp = copy.createPageStamp(page);</code></pre></li><li>Create a Chunk to hold the text. <code>com.itextpdf.text.Chunk</code> represents a block of text which can be assigned text properties like font etc.<pre><code>Chunk chunk = new Chunk(String.format("Page %d of %d", pageNumber, totalPageCount));
Font font = new Font();
font.setFamily(Font.FontFamily.HELVETICA.name());
font.setSize(8);
font.setStyle(Font.FontStyle.ITALIC.getValue());
chunk.setFont(font);</code></pre></li><li>Add text into the PageStamp. The text location starts at the bottom left of the page, increasing from left to right horizontally and bottom to top vertically.<pre><code>ColumnText.showTextAligned(stamp.getUnderContent(), Element.ALIGN_RIGHT, new Phrase(chunk), 580, 10, 0);</code></pre></li><li>Add the new page to the merged PDF<pre><code>copy.addPage(page);</code></pre></li></ol>Here is the full code I used for merging 3 PDF files.<pre><code>package com.aoj.pdf;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfCopy.PageStamp;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
public class ItextPdfMergePaginate {
public static void main(String[] args) {
List<InputStream> pdfs = new ArrayList<InputStream>();
try (FileInputStream fis1 = new FileInputStream("c:\\test\\1.pdf");
FileInputStream fis2 = new FileInputStream("c:\\test\\2.pdf");
FileInputStream fis3 = new FileInputStream("c:\\test\\3.pdf");) {
pdfs.add(fis1);
pdfs.add(fis2);
pdfs.add(fis3);
OutputStream output = new FileOutputStream("c:\\test\\merge.pdf");
mergeAndPaginate(pdfs, output);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void mergeAndPaginate(List<InputStream> streamOfPDFFiles, OutputStream outputStream) {
Document document = new Document(PageSize.LETTER);
try {
// Open PdfCopy for to copy the merged document into outputStream
PdfCopy copy = new PdfCopy(document, outputStream);
document.open();
// We will use the list of readers to get total page count and
// process individual pages later
List<PdfReader> readers = new ArrayList<PdfReader>();
int totalPageCount = 0;
for (InputStream file : streamOfPDFFiles) {
// Create Reader for each input stream and add to reader list
PdfReader reader = new PdfReader(file);
readers.add(reader);
totalPageCount += reader.getNumberOfPages();
}
// Number of pages processed so far.
int currentPageNumber = 0;
for (PdfReader reader : readers) {
int pageCount = reader.getNumberOfPages();
// Page Number starts with 1.
for (int i = 1; i <= pageCount; i++) {
int pageNumber = currentPageNumber + i;
// Process one page at a time
PdfImportedPage page = copy.getImportedPage(reader, i);
PageStamp stamp = copy.createPageStamp(page);
// Create chunk of text with page information and set font settings
Chunk chunk = new Chunk(String.format("Page %d of %d", pageNumber, totalPageCount));
Font font = new Font();
font.setFamily(Font.FontFamily.HELVETICA.name());
font.setSize(8);
font.setStyle(Font.FontStyle.ITALIC.getValue());
chunk.setFont(font);
// Write the text into page (represented by stamp object
ColumnText.showTextAligned(stamp.getUnderContent(), Element.ALIGN_RIGHT, new Phrase(chunk), 580, 10, 0);
stamp.alterContents();
// Add page after page info is written.
copy.addPage(page);
}
currentPageNumber += pageCount;
}
outputStream.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (document.isOpen())
document.close();
try {
if (outputStream != null)
outputStream.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
}</code></pre>And here is the Gradle build file used for this example<pre><code>apply plugin:'application'
mainClassName = "com.aoj.pdf.ItextPdfMergePaginate"
applicationName = 'java-pdf-examples'
repositories {
mavenCentral()
}
dependencies {
compile group: 'com.itextpdf', name: 'itextpdf', version: '5.5.12'
}</code></pre>abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com2tag:blogger.com,1999:blog-18313336.post-85917876318823205622017-09-06T21:42:00.001-04:002017-09-06T21:42:12.136-04:00Merge PDF files using iText 5This is an example code for a simple PDF merge using iText 5. We use three <code>InputStream</code>s in a List as input and merged file is written to the file system.
<a name='more'></a>
<pre><code>package com.aoj.pdf;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import com.itextpdf.text.Document;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfReader;
public class ItextPdfMerge {
public static void main(String[] args) {
List<InputStream> pdfs = new ArrayList<InputStream>();
try (FileInputStream fis1 = new FileInputStream("c:\\test\\1.pdf");
FileInputStream fis2 = new FileInputStream("c:\\test\\2.pdf");
FileInputStream fis3 = new FileInputStream("c:\\test\\3.pdf");) {
pdfs.add(fis1);
pdfs.add(fis2);
pdfs.add(fis3);
OutputStream output = new FileOutputStream("c:\\test\\merge.pdf");
// Merge PDF files.
mergePdfs(pdfs, output);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void mergePdfs(List<InputStream> streamOfPDFFiles, OutputStream outputStream) {
// Create Document object with PageSize set to Letter.
Document document = new Document(PageSize.LETTER);
try {
// Open PdfCopy for to copy the merged document into outputStream
PdfCopy copy = new PdfCopy(document, outputStream);
document.open();
for (InputStream file : streamOfPDFFiles) {
// Create Reader for each input stream
PdfReader reader = new PdfReader(file);
// Merge each pdf into merged document represented by copy
copy.addDocument(reader);
}
outputStream.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (document.isOpen())
document.close();
try {
if (outputStream != null)
outputStream.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
}</code></pre>
Following is the gradle build file used to run this example.<pre><code>apply plugin:'application'
mainClassName = "com.aoj.pdf.ItextPdfMerge"
applicationName = 'java-pdf-examples'
repositories {
mavenCentral()
}
dependencies {
compile group: 'com.itextpdf', name: 'itextpdf', version: '5.5.12'
}
</code></pre>abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com0tag:blogger.com,1999:blog-18313336.post-81612691684387509652017-09-04T20:57:00.000-04:002017-09-04T20:57:06.049-04:00WatchService to monitor Directories for changesThere a many scenarios where you would like to monitor a directory for new files, or changes to existing files or deleted files. Some of the use cases are<ul><li>Files will be dropped into a directory by a third party which have to be processed by your application</li><li>A file editor which monitors the directory to make sure the files currently being edited are not modified by another concurrent user.</li><li>You want to start a build and deploy code whenever a source file is changed (In an enterprise application, this is usually done in a source control in conjunction with a tool like Jenkins).</li></ul>Starting Java 7, the new <code>java.nio.file.WatchService</code> provides a scalable solution to monitor directory for any changes. In this post, we will go over the features of the WatchService service and a simple example for how to monitor a directory for changes and print the name of the file that was affected.
<a name='more'></a>
<h3>WatchService Basics</h3>
The solution for implementing WatchService to monitor consists of the following main elements<ul><li><b>WatchService</b>: The actual Service that monitors the registered objects (directories) for changes</li><li><b>Watchable</b>: Any object implementing java.nio.file.Watchable interface can be registered with the WatchService. Currenly only implementation for Watchable is <code>java.nio.file.Path</code></li><li><b>WatchKey</b>: A watch key is an object that represents the registration for a Watchable on to a WatchService. A key object is used to signal the application code of any changes to the Directory. A key is created at the time of registration and will be active until one of the following three events occurs<ul><li>The cancel method is invoked on the WatchKey.</li><li>Cancelled implicitly (object is no longer accessible)</li><li>Th associated WatchService is closed.</li></ul></li></ul><h3>Steps to implement WatchService to monitor a Directory</h3><ol><li>Create a WatchService: WatchService can be created by invoking newWatchService() method like below<pre><code>WatchService watchService = FileSystems.getDefault().newWatchService();</code></pre></li><li>Register the directory which has to be monitored.<pre><code>Path dir = Paths.get("c:/test/");
dir.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.ENTRY_MODIFY);</code></pre>There are 4 StandardWatchEventKinds<ul><li><b>ENTRY_CREATE</b>: A directory entry (file/directory) is created</li><li><b>ENTRY_DELETE</b>: A directory entry is deleted.</li><li><b>ENTRY_MODIFY</b>: A directory entry is modified.</li><li><b>OVERFLOW</b>: Indicates that events might have been lost or discarded. OVERFLOW is implicitly registered and need not be registered again.</li></ul></li><li>An infinite loop waiting for events. When an event occurs, the key is signaled and placed into the watcher's queue.</li><li>Retrieve the key from the watcher's queue. A key from the watcher's queue can be retrieved by either using the take() or poll() methods on the WatchService. take() waits for an event, where as poll has two versions either to return instantly or wait for a specified time.<pre><code>//Wait till next event.
key = watchService.take();</code></pre><pre><code>//Retrieve the event and remove the next watch key, returns null if no keys are present.
key = watchService.poll();</code></pre><pre><code>//Wait for 10 minutes for keys, return null after 10 minutes.
key = watchService.poll(10, TimeUnit.MINUTES);</code></pre></li><li>Retrieve events from key and process. There can be multiple events for a key.<pre><code>for (WatchEvent<?> event : key.pollEvents()) {...}</code></pre></li><li>Reset the key using key.reset() method. If the key is not reset(), it will not be able to receive any further events. If the reset() method returns false, it means that the key is not valid any more and you can exit the loop.</li><li>Close the service: The watch service exits when either the thread exits or when it is closed (by invoking its closed method).</li></ol><h3>Full code for a service to monitor a directory for changes and print the name of the file that was affected</h3>In this example, we use the take() method to retrieve the key, and monitor only for StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE and StandardWatchEventKinds.ENTRY_MODIFY events on the directory. The only action we take in case of an event is to print the filename.<pre><code>package files;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
public class WatchServiceTest {
public static void main(String[] args) {
try {
WatchService watchService = FileSystems.getDefault().newWatchService();
Path dir = Paths.get("c:/test/");
dir.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.ENTRY_MODIFY);
for (;;) {
WatchKey key = null;
// Retrieve key from WatchService Queue.
try {
key = watchService.take();
} catch (InterruptedException e) {
return;
}
// Process each event for the key.
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
// OVERFLOW is implicitly registered.
if (kind == StandardWatchEventKinds.OVERFLOW) {
continue;
}
WatchEvent<Path> ev = (WatchEvent<Path>) event;
// WatchEvent.context is the filename and can be used for further processing. In
// this example, we just print the filename.
Path filename = ev.context();
System.out.println(filename + " even " + kind);
}
// Reset key to be able to retrieve further events.
// Break if key is invalid. (reset() returns false.)
if (!key.reset())
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}</code></pre>abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com0tag:blogger.com,1999:blog-18313336.post-70876108975769835312017-09-01T20:10:00.000-04:002017-09-01T20:41:19.094-04:00Directory Listing in JavaThis post provides a examples of a few ways to list contents of a directory in Java. A couple of examples of how to recursively traverse a directory are also provided. Finally we will see the use of <code>Files.walk()</code> and <code>Files.find()</code> introduced in Java 8, which makes directory traversal even more simple.<br />
<a name='more'></a>
<h3>List files using Files.list()</h3>
The simple Files.list() will list all files, including sub-directories. But will not go through listing sub-directories recursively.<pre><code>Files.list(Paths.get("c:/test/")).filter(Files::isRegularFile).forEach(System.out::println);</code></pre>
<h3>List files using Files.list(), skipping sub-directories</h3>
We can use a filter() to filter out sub-directories and list only regular files<pre><code>Files.list(Paths.get("c:/test/")).filter(Files::isRegularFile).forEach(System.out::println);</code></pre>
<h3>List files using DirectoryStream</h3>
<pre><code>Files.newDirectoryStream(Paths.get("c:/test/")).forEach(System.out::println);</code></pre>
<h3>Recursively List files in a directory using DirectoryStream</h3>
This example uses a recursive function to collect files in a directory and it's subdirectories into a list and print it.
<pre><code>public static void listFiles(Path path, List<Path> files) throws IOException {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
for (Path file: stream) {
if (Files.isDirectory(file)) {
listFiles(file, files);
}
files.add(entry);
}
}
}</code></pre>This method can be invoked as below<pre><code>List<Path> files = new ArrayList<Path>();
listFiles(Paths.get("c:/test/"), files);
files.forEach(System.out::println);</code></pre>
<h3>Recursively List files in a directory using Files.walkFileTree</h3>
<code>Files.walkFileTree</code> provides a simpler way than the above solution to traverse a directory and it's sub-directories. walkFileTree takes a FileVisitor as a parameter, for this example we will write a simple FileVisitor implementation which will add the files to a list.<pre><code>Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (Files.isRegularFile(file)) {
visitorFiles.add(file);
}
return FileVisitResult.CONTINUE;
}
});
visitorFiles.forEach(System.out::println);
}</code></pre>
<h2>Directory Traversal using Java 8 Files.walk() and Files.find()</h2>
Java 8 adds a couple of methods to the <code>java.nio.file.Files</code> that make recursive directory travesal much simpler.
<code>Files.walk()</code> does a depth-first traversal of a directory, and can be used as below to process all files in a directory including the sub-directories.<pre><code>Files.walk(Paths.get("C:/test/")).filter(Files::isRegularFile).forEach(System.out::println);</code></pre><code>Files.find()</code> is also traverses the directory tree in depth-first manner, but also takes a BiPredicate as another parameter which is applied to each Path element encountered in the traversal.<pre><code>Files.find(Paths.get("C:/test/"), Integer.MAX_VALUE, (filePath, attrs) -> attrs.isRegularFile()).forEach(System.out::println);</code></pre>
abhihttp://www.blogger.com/profile/05788965755655733389noreply@blogger.com1