Tag Archives: java

Lambda: simplify method calls

There is important part of good programmers skills – ability to detect duplicity. Over years I have developed it for various situations. But recently I have added new situation – duplicity in calling methods with many parameters. And especially with many parameters in local scope. Take a look on following example:

package test;

import java.awt.Graphics;

public class NaiveRenderer {
	
	public void render(Graphics g, int paramA, boolean paramB, double paramC, String paramD) {
		int calculatedA = paramA+42;
		
		if (paramA<100) {
			renderSubpart(g, !paramB, paramC*22.3, paramD+" oh", calculatedA, -1.0);
		} else if (paramA<10) {
			renderSubpart(g, !paramB, paramC*22.3, paramD+" oh", calculatedA, -0.2);
		} else if (paramA==0) {
			renderSubpart(g, !paramB, paramC*22.3, paramD+" oh", calculatedA, 0.0);
		} else if (paramA>100) {
			renderSubpart(g, !paramB, paramC*22.3, paramD+" oh", calculatedA, 1.0);
		} else if (paramA>10) {
			renderSubpart(g, !paramB, paramC*22.3, paramD+" oh", calculatedA, 0.2);
		} else {
			renderSubpart(g, !paramB, paramC*22.3, paramD+" oh", calculatedA, 0.0);
		}
	}
	
	public void renderSubpart(Graphics g, boolean paramB, double paramC, String paramD, int calculatedA, double calculatedB) {
		//...actual code
	}
}

Obviously, there is huge duplicity in renderSubpart calls. Calculation of some parameters is repeated many times. Let’s improve it:

package test;

import java.awt.Graphics;

public class BetterRenderer {
	
	public void render(Graphics g, int paramA, boolean paramB, double paramC, String paramD) {
		int calculatedA = paramA+42;
		
		boolean newParamB = !paramB;
		double newParamC = paramC*22.3;
		String newParamD = paramD+" oh";
		
		if (paramA<100) {
			renderSubpart(g, newParamB, newParamC, newParamD, calculatedA, -1.0);
		} else if (paramA<10) {
			renderSubpart(g, newParamB, newParamC, newParamD, calculatedA, -0.2);
		} else if (paramA==0) {
			renderSubpart(g, newParamB, newParamC, newParamD, calculatedA, 0.0);
		} else if (paramA>100) {
			renderSubpart(g, newParamB, newParamC, newParamD, calculatedA, 1.0);
		} else if (paramA>10) {
			renderSubpart(g, newParamB, newParamC, newParamD, calculatedA, 0.2);
		} else {
			renderSubpart(g, newParamB, newParamC, newParamD, calculatedA, 0.0);
		}
	}
	
	public void renderSubpart(Graphics g, boolean paramB, double paramC, String paramD, int calculatedA, double calculatedB) {
		//...actual code
	}
}

Hm. So we have bloated scope by three new local variables. And we have to name it. Plus there is still problem with many similar calls to the renderSubpart. But only one parameter varies. Let’s improve that:

package test;

import java.awt.Graphics;

public class EvenBetterRenderer {
	
	public void render(Graphics g, int paramA, boolean paramB, double paramC, String paramD) {
		double calculatedB;
		
		if (paramA<100) {
			calculatedB = -1.0;
		} else if (paramA<10) {
			calculatedB = -0.2;
		} else if (paramA==0) {
			calculatedB = 0.0;
		} else if (paramA>100) {
			calculatedB = 1.0;
		} else if (paramA>10) {
			calculatedB = 0.2;
		} else {
			calculatedB = 0.0;
		}
		
		renderSubpart(g, !paramB, paramC*22.3, paramD+" oh", paramA+42, calculatedB);
	}
	
	public void renderSubpart(Graphics g, boolean paramB, double paramC, String paramD, int calculatedA, double calculatedB) {
		//...actual code
	}
}

So now we reduced number of added local variables to one. Great, but I don’t like decoupling of condition and method call. Block of condition just set calculatedB which is later used for calling renderSubpart. Can’t we improve that?

I realized that I can wrap parameters into local lambda function like this:

package test;

import java.awt.Graphics;
import java.util.function.Consumer;

public class LambdaRenderer {
	
	public void render(Graphics g, int paramA, boolean paramB, double paramC, String paramD) {
		Consumer<Double> renderSubpartLambda = (calculatedB)->renderSubpart(g, !paramB, paramC*22.3, paramD+" oh", paramA+42, calculatedB);
		
		if (paramA<100) {
			renderSubpartLambda.accept(-1.0);
		} else if (paramA<10) {
			renderSubpartLambda.accept(-0.2);
		} else if (paramA==0) {
			renderSubpartLambda.accept(0.0);
		} else if (paramA>100) {
			renderSubpartLambda.accept(1.0);
		} else if (paramA>10) {
			renderSubpartLambda.accept(0.2);
		} else {
			renderSubpartLambda.accept(0.0);
		}
	}
	
	public void renderSubpart(Graphics g, boolean paramB, double paramC, String paramD, int calculatedA, double calculatedB) {
		//...actual code
	}
}

So I have defined renderSubpartLambda that receives single varying parameter and fill all other parameters that shares value over all calls. This is possible because Lambda function, unlike methods, have access to the local scope (parameters, local variables). Lambda is then executed from exact position withing condition blocks with only with single important parameter.

This technique is usable in all situations where it would be hard to define helper method because number of passed parameters would be too high. Btw. this solution is language independent – I have used it in JavaScript too.

Advertisements

SimpleDateFormat is NOT immutable

Yes, SimpleDateFormat is not immutable as name may suggest. This came as complete surprise to me. When using from multiple threads then appeared exceptions like:

 java.lang.NumberFormatException: For input string: ""
 at java.lang.NumberFormatException.forInputString
(NumberFormatException.java:65)
 at java.lang.Long.parseLong(Long.java:601)
 at java.lang.Long.parseLong(Long.java:631)
 at java.text.DigitList.getLong(DigitList.java:195)
 at java.text.DecimalFormat.parse(DecimalFormat.java:2051)
 at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2162)
 at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
 at java.text.DateFormat.parse(DateFormat.java:364)

Quick check with documentation brought suspicion:

Date formats are not synchronized. It is recommended to create separate 
format instances for each thread. If multiple threads access a format 
concurrently, it must be synchronized externally.

Yes, it was enough to create per-thread SimpleDateFormat.

I think SimpleDateFormat is lousy name and also SimpleDateFormat breaks single responsibility principle. Much better would be decomposition into multiple classes:

  • SimpleDateFormat – immutable object only holding format of date
  • SimpleDateFormatter – mutable object used for formatting according to passed SimpleDateFormat
  • SimpleDataParser – mutable object used for parsing according to passed SimpleDateForma

Gradle: Spring + FatJar = dependency on Internet connection

See my recent blog post for FatJar configuration sample. Today I found nasty behavior of Gradle plugin FatJar when used on Spring project. I hope that this post will help you not to spend whole day with it – as I did.

If your project uses only one version of each library, java packages system should assure that there will be no conflicts when merging multiple jar libraries into one big. But that does not apply to directory META-INF. This directory typically does not use packages system, so conflicts may appear.

FatJar plugin handles this situation in simple way – it just copies each file in multiple versions:

mess

That – of course – causes issues when loading. Typically only one file is picked. For example Spring stores in spring.schemas paths in resources where XSD schema files referred from your beans.xml are located in resources (so it does not need to load it from Internet). But do that for each module – Context, AOP, Web, … So only one module works.

This problem does not appear on machine with available Internet connection, because it just downloads schemas from addresses like http://www.springframework.org/schema/beans/spring-beans-3.0.xsd. But when you deploy your app on intranet server, problem appears:


143306.358000 2016-01-26 [ main] [ WARN] [factory.xml.XmlBeanDefinitionReader] [] : Ignored XML validation warning
org.xml.sax.SAXParseException: schema_reference.4: Failed to read schema document 'http://www.springframework.org/schema/beans/spring-beans-3.0.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not &amp;lt;xsd:schema&amp;gt;.
at

....
Caused by: java.net.UnknownHostException: www.springframework.org
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:184) ~[?:1.8.0_72-internal]
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) ~[?:1.8.0_72-internal]
at java.net.Socket.connect(Socket.java:589) ~[?:1.8.0_72-internal]
at java.net.Socket.connect(Socket.java:538) ~[?:1.8.0_72-internal]

And then:

Exception in thread &quot;main&quot; org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 6 in XML document from class path resource [grab_mode_beans.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 6; columnNumber: 69; cvc-elt.1: Cannot find the declaration of element 'beans'.
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:399)
....
Caused by: org.xml.sax.SAXParseException; lineNumber: 6; columnNumber: 69; cvc-elt.1: Cannot find the declaration of element 'beans'.
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:203)
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:134)

Solution is to use shadowJar. It may look like this:

buildscript {
  repositories {
    maven {
      url "https://maven.eveoh.nl/content/repositories/releases"
    }

    mavenCentral()
      jcenter()
    }

  dependencies {
    classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.2'
  }
}

apply plugin: 'com.github.johnrengelman.shadow'

dependencies {
  compile project(":MyOwnProjectExample")
}

shadowJar {
archiveName "MyTest.jar";

append("META-INF/spring.schemas")
append("META-INF/spring.handlers")

manifest {
  attributes("Main-Class": "com.my.Test" )
  }
}

//this helps if you like to build fatJar as part of normal build
//otherwise use "gradle shadowJar";
assemble.dependsOn shadowJar
build.dependsOn shadowJar

I already suffered at least by 3 similar issues with following libraries:
* Spring
* Log4j2
* Lucene

I hope it helps!

How to connect VisualVM to directly invisible server using single port

Situation

I would like to check JVM state on my server using VisualVM and JMX. But I can’t connect directly to it because is behind firewall or in inaccessible network. Luckily I can connect through SSH to machine which can access my server.

 

situation

Naïve setup

I need to enable JMX for my application on server. Add following parameters into java command line of application:


-Dcom.sun.management.jmxremote.port=9872

-Dcom.sun.management.jmxremote.ssl=false

-Dcom.sun.management.jmxremote.authenticate=false

Check that you can connect to your application with this setting when debugging on local computer using JMX:

localconn.

Naïve solution

OK, so it works locally, great! Now try to deploy your app to server and try to run ssh with port forwarding from your computer:


ssh -L 9872:192.168.11.52:9872 user@72.15.87.44

So try to redirect port 9872 on server through tunnel between my and mediator computer to my local port 9872. But when I try to connect to localhost 9872 I get message:

error

(“Cannot connect to localhost:9872 using service:jmx:rmi:////jndi/rmi://localhost:9872/jmxrmi”)

The Problem

Beside communication on JMX port (in my case 9872) VisualVM tries to communicate by random other port using RMI. But because only one port was redirected this fails.

rmi_fail

Working setup

So let’s try to add 2 more parameters that will fix interface for RMI to 127.0.0.1:9872. So only one port will be used:


-Djava.rmi.server.hostname=127.0.0.1

-Dcom.sun.management.jmxremote.rmi.port=9872

-Dcom.sun.management.jmxremote.port=9872

-Dcom.sun.management.jmxremote.ssl=false

-Dcom.sun.management.jmxremote.authenticate=false

I use 127.0.0.1 because that should work on all computers and therefore this setting is suitable for installation package. If you can use fixed IP address you can avoid nesting of SSH tunnel below. But usage of loopback interface is more secure because should not be visible from outside of machine.

Working solution

 

So now lets try to do nested port forwarding, please check that port 9872 is available on both mediator and your computer. If not, choose different one. On my computer launch:


ssh -L 9872:localhost:9872 user@72.15.87.44

That will open tunnel between my computer and mediator. Then on mediator (you can use opened console from command above) execute:


ssh -L 9872:127.0.0.1:9872 user2@192.168.11.52

And that will open tunnel between mediator and server. Add JMX connection to localhost:9872:

localconn

And voilà:

result

Gradle + Jar (FatJar) : “Could not copy zip entry” error message

This problem is caused by https://discuss.gradle.org/t/ziptree-unable-to-overwrite-temporary-read-only-files/2322/3 resp. https://issues.gradle.org/browse/GRADLE-2959

Solution is to add delete command which removes folder ./tmp/expandedArchives:


jar {
  delete "$buildDir/tmp/expandedArchives"

  from {
    (configurations.runtime).collect {
      it.isDirectory() ? it : zipTree(it)
    }
  }

  manifest {
    attributes("Main-Class": "com.test.Main" )
    }
  }

Gradle + Eclipse plugin: Add AspectJ nature into projects

I have found nice script for adding AspectJ nature into Eclipse project using Gradle. See https://github.com/breskeby/gradleplugins/blob/0.9-upgrade/aspectjPlugin/aspectJ.gradle#L29 . Unfortunately each run of ‘gradle eclipse’ adds new nodes into project XML. Here is my fix of that issue:


eclipse.project.file.withXml { xmlProvider->
  def projectDescription = xmlProvider.asNode()
  def xmlparser = new XmlParser()

  def builders = projectDescription.buildSpec[0]

  if (!builders.buildCommand.any {it.name[0].value()=='org.eclipse.ajdt.core.ajbuilder'}) {
    def ajbuilder = xmlparser.createNode(builders, 'buildCommand', [:])
    xmlparser.createNode(ajbuilder, 'name', [:]).setValue('org.eclipse.ajdt.core.ajbuilder')
    xmlparser.createNode(ajbuilder, 'arguments', [:]);
  }

  def natures = projectDescription.natures[0]

  if (!natures.nature.any {it.value()=='org.eclipse.ajdt.ui.ajnature'}) {
    def ajnature = xmlparser.createNode(null, 'nature', [:])
    ajnature.setValue('org.eclipse.ajdt.ui.ajnature');
    natures.children().add(0, ajnature)
  }
}

Then all nodes are created only once.

Gradle + Eclipse plugin: Remove build folder from Eclipse project

By default Eclipse plugin does not add /build folder into ignored resources and that may cause /build folder to be validated. Then many warnings will appear in Markers tab of Eclipse. Beside that it may be performance problem.

I found almost suitable solution here: https://discuss.gradle.org/t/eclipse-pluging-adding-resource-filters/5408 Unfortunately it adds new filter into configuration during each ‘gradle eclipse’. Here is my fix for that situation:


eclipse.project.file.withXml { xmlProvider ->
  Node project = xmlProvider.asNode()
  Node node = project

  if (node.filteredResources.isEmpty()) {
    node = node.appendNode('filteredResources')
  } else {
    node = node.filteredResources[0]
  }

  if (!node.filter.any {it.id[0].value()[0]=='1447321705713'}) {
    Node filter = node.appendNode('filter')

    filter.appendNode('id', '1447321705713')
    filter.appendNode('name', '')
    filter.appendNode('type', 10)
    Node matcher = filter.appendNode('matcher')
    matcher.appendNode('id', 'org.eclipse.ui.ide.multiFilter')
    matcher.appendNode('arguments', '1.0-name-matches-false-false-build')
  }
}

So filter node is added only in case it does not already exists.