Dienstag, 2. Oktober 2012

Overview Parameterized Tests with JUnit

Gerard Meszaros's describes in his great book with the title xUnit Test Patterns a pattern with the name Parameterized Test. This blog post describes how the pattern can be implemented in a JUnit 4.X test. The post compares three different options.

1. JUnit Parameterized Test

The JUnit framework comes with a runner for parameterized tests. The parameters are defined by a static function which is marked with the annotation @Parameters. The JUnit Runner is called Parameterized.

Example: 
import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class JUnitParameterizedTest {
static class Person {
final String name;
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return String.format("Person[name: %s]", name);
}
}
@Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
new Object[]{"Christian"},
new Object[]{"Joshua"},
});
}
String name;
public JUnitParameterizedTest(String name) {
this.name = name;
}
@Test
public void createPersonWithName(){
Person person = new Person(name);
assertEquals(name, person.name);
}
}
Output - Eclipse JUnit View: 
Advantages
No extra framework or library for parameterized tests is needed. The JUnit view in eclipse and also in other IDEs works fine. One test with one defined parameter set can be invoked via the JUnit view in eclipse.

Disadvantages
The output from the tests is not clear. The output shows only the index number of the used test parameter. Only one test data model and parameter set per test class.

2. More JUnit Parameterized Test in a Test Class

It is possible to have more then one parameterized JUnit test in one test class by using the experimental runner "Enclosed".

Example: 
import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Enclosed.class)
public class JUnitEnclosedParameterizedTest {
static class Person {
final String name;
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return String.format("Person[name: %s]", name);
}
}
@RunWith(Parameterized.class)
public static class PersonNameTest {
@Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
new Object[]{"Christian"},
new Object[]{"Joshua"},
});
}
String name;
public PersonNameTest(String name) {
this.name = name;
}
@Test
public void createPersonWithName(){
Person person = new Person(name);
assertEquals(name, person.name);
}
}
@RunWith(Parameterized.class)
public static class PersonTest {
@Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
new Object[]{new Person("Christian")},
new Object[]{new Person("Joshua")},
});
}
Person person;
public PersonTest(Person person) {
this.person = person;
}
@Test
public void savePerson() {
// TODO: Implementation test logic
}
}
}

Output - Eclipse JUnit View:
Advantages
Grouping logic tests together in one class. Each test can be run from the JUnit view, a single test can be executed for debugging.

Disadvantages
Lots of boilerplate code of the embedded classes.

3. TwiP

TwiP is JUnit extension for parameterized tests. The library brings a JUnit runner, which is named "TwiP".

Example: 
import static org.junit.Assert.*;
import net.sf.twip.AutoTwip;
import net.sf.twip.TwiP;
import net.sf.twip.Values;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(TwiP.class)
public class TwiPTest {
static class Person {
final String name;
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return String.format("Person[name: %s]", name);
}
}
public static final String[] names =new String[]{
"Christian",
"Joshua"
};
@Test
public void createPersonWithName(@Values("names") String name){
Person person = new Person(name);
assertEquals(name, person.name);
}
public static final Person[] defaultPersons = new Person[]{
new Person("Christian"),
new Person("Joshua")
};
@Test
public void savePerson(@Values("defaultPersons") Person person) {
// TODO: Implementation test logic
}
@AutoTwip
public static Person randomPersons(String name){
return new Person(name);
}
@Test
public void savePersonWithRandomName(Person person){
// TODO: Implementation test logic
}
}
view raw TwiPTest.java hosted with ❤ by GitHub

Output - Eclipse JUnit View: 

Advantages
More then one parameterized test in a class is possible. Mixing parameterized and not parameterized tests is possible in one test class. Clear test output toString() method is used for the test parameters.

Disadvantages
A single test could not be chosen from the JUnit output (Eclipse JUnit view) and could not be invoked. This makes debugging the tests difficult because always all test combination must be executed to debug one failing test with one special combination.

4. JUnit Params

JUnit Params is another JUnit extension for parameterized tests like TwiP. The essential difference between TwiP and JUnit Params are the syntax how to define the parameterized tests.

Example: 
package demo;
import static org.junit.Assert.*;
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(JUnitParamsRunner.class)
public class JUnitParamsTest {
static class Person {
final String name;
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return String.format("Person[name: %s]", name);
}
}
@Test
@Parameters({"Christian", "Joshua"})
public void createPersonWithName(String name) {
Person person = new Person(name);
assertEquals(name, person.name);
}
@Test
@Parameters(method="defaultPersons")
public void savePerson(Person person) {
}
Object[] defaultPersons() {
return new Object[]{new Person("Christian"), new Person("Joshua")};
}
}

Output - Eclipse JUnit View: 


Advantages
Same advantages as TwiP and a little bit clearer test output then TwiP.

Disadvantages
Same disadvantages as TwiP a single test could not be invoked.

5. Summary

A perfect solution for a parameterized test in JUnit does not exists. TwiP and JUnitParams provided the way I like to write parameterized tests. But TwiP and also JUnitParams test cannot be debugged a single test can not be executed. I think the problems lies in the JUnit design for the descriptions and not in the TwiP or the JUnitParams project. Hope there will be a better solution in the future. So it's a difficult choice

Dienstag, 25. September 2012

Performance Apache Common StringUtils Split and Google Guava Splitter

Last Friday I have a discussion with a colleague at SEITENBAU about the semantic of the split method of the Apache common lang StringUtils class. At the end we have compared the Google Guava Splitter API with the Apache commons Lang StringUtils split methods. Our opinion after that is that the source code based on Guava could be better understood and is much clearer.

After comparing the APIs, we have thought about which of the two APIs has the faster split implementation. So I have build simple performance test for the two String split implementations. The result has surprised me. The StringUtils split method is in my test case much faster then the Guava Splitter split method.

Test setup is I generate 5000 random strings with a length of 10000. The test strings contains commas to split the strings in the test. I invoke the Apache common spilt method and the Guava Splitter with the same test data, the performance result is shown in the table bellow.

Test Runs 1 2 3 4
Apache Common
StringUtils.split(…)
126 ms 122 ms 121 ms 122 ms
Google Guava
splitter.split(…)
352 ms 350 ms 346 ms 349 ms


Here the source of my simple performance test:
import static org.junit.Assert.assertTrue;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.util.StopWatch;
import com.google.common.base.Splitter;
public class StringUtilsTest
{
static int testDataCount = 5000;
static int testDataStringSize = 10000;
static List<String> testData = new LinkedList<String>();
static StopWatch stopWatch = new StopWatch();
@BeforeClass
public static void generateTestData() {
for(int i=0; i < testDataCount; i++){
String data = RandomStringUtils
.random(testDataStringSize, "ABCDEFGHIJKLMNOPQRSTUVXYZ,");
testData.add(data);
}
}
@AfterClass
public static void printTestSummery(){
System.out.println(stopWatch.prettyPrint());
}
@Test
public void apacheCommonLangSplit() throws Exception {
stopWatch.start("Apache Common Lang Split");
for(String data: testData){
String[] elements = StringUtils.split(data, ",");
for (String element : elements) {
assertTrue(element.length() < testDataStringSize);
}
}
stopWatch.stop();
}
@Test
public void guavaSplitterSplit() throws Exception {
stopWatch.start("Google Guava Splitter");
Splitter spiltter = Splitter.on(",");
for(String data: testData){
Iterable<String> elements = spiltter.split(data);
for (String element : elements) {
assertTrue(element.length() < testDataStringSize);
}
}
stopWatch.stop();
}
}

Why
Has anybody an idea why the Guava API in my test is slower then the StringUtils split method? I read that the Guava Splitter performance should be very good. Therefore, I am surprised about the result.

Here the dependencies I have used for the performance test:
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>12.0</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.1.2.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
view raw pom.xml hosted with ❤ by GitHub

Sonntag, 9. September 2012

Equinox CM and ECF inconsistent Behavior

This evening I had a long OSGi debugging session with the Equinox Configuration Admin and ECF based Remote Services implementation. In the end I found out, it was my mistake used configuration admin wrong. And I update this blog post.

But the problem is that the behavior of the configuration admin depends on which bundles calls the createFactoryConfiguration(...) method and this makes debugging hard.

The problem was that when I create the first time a factory configuration via my remote bundle (which is running on the same system local in other OSGi framework), I become a exception. The remote bundle invokes the method "createWall(…)" see the code sample:
/**
* This method is provided to remote bundles as a remote service.
*/
public void createWall(int x, int y, int z, int length, int height, int rotate) {
try {
Configuration configuration =
configurationAdmin.createFactoryConfiguration(WALL_PID, null);
configuration.update();
Dictionary<String, Object> wallProps = configuration.getProperties();
wallProps.put("x", x);
wallProps.put("y", y);
wallProps.put("z", z);
wallProps.put("length", length);
wallProps.put("height", height);
wallProps.put("rotate", rotate);
configuration.update(wallProps);
} catch (IOException e) {
e.printStackTrace();
}
}
view raw gistfile1.java hosted with ❤ by GitHub

When the first caller of this method was the remote bundle I become the following exception (when the second caller of the configuration admin is a local bundle got the same exception, e.g. when a configuration is created via the apache webconsole):
java.io.IOException: No such file or directory
at java.io.UnixFileSystem.createFileExclusively(Native Method)
at java.io.File.createNewFile(File.java:883)
at org.eclipse.equinox.internal.cm.ConfigurationStore.writeConfigurationFile(ConfigurationStore.java:112)
at org.eclipse.equinox.internal.cm.ConfigurationStore$1.run(ConfigurationStore.java:99)
at java.security.AccessController.doPrivileged(Native Method)
at org.eclipse.equinox.internal.cm.ConfigurationStore.saveConfiguration(ConfigurationStore.java:97)
at org.eclipse.equinox.internal.cm.ConfigurationImpl.update(ConfigurationImpl.java:243)
at org.eclipselabs.occ.marsrobot.remote.host.WorldComponent.createWall(WorldComponent.java:42)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.eclipse.ecf.provider.remoteservice.generic.RemoteServiceRegistrationImpl.callService(RemoteServiceRegistrationImpl.java:356)
at org.eclipse.ecf.provider.remoteservice.generic.RegistrySharedObject$11.run(RegistrySharedObject.java:1375)
at org.eclipse.equinox.concurrent.future.SingleOperationFuture$1.run(SingleOperationFuture.java:96)
at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
at org.eclipse.equinox.concurrent.future.SingleOperationFuture.runWithProgress(SingleOperationFuture.java:89)
at org.eclipse.ecf.core.jobs.JobsExecutor.safeRun(JobsExecutor.java:52)
at org.eclipse.ecf.core.jobs.JobsExecutor$1.run(JobsExecutor.java:79)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)
view raw gistfile1.txt hosted with ❤ by GitHub

When the same logic is called first time from a local bundle everything works fine. After some time of debugging, I found the issue. The point is not that the bundle is local or remote.

In the implementation of the method "createWall(...)" the Configuration Admin method "createFactoryConfiguration(...)" with location null is used. The JavaDoc of this method says, when this method is called the first time, with location null, then the location of the first bundle is used which register a service.

OSGi Compendium Specification JavaDoc for the createFactoryConfiguration says:
"The Configuration is bound to the location specified. If this location is null it will be bound to the location of the first bundle that registers a Managed Service Factory with a corresponding PID."

In my case the first bundle was sometimes indirect the remote bundle. So I have the problem and become the exception. My fix was to set the location to the bundle location of the bundle which creates the wall configuration, see the code sample:
@Activate
public void activate(BundleContext context){
bundleLocation = context.getBundle().getLocation();
}
public void createWall(int x, int y, int z, int length, int height, int rotate) {
try {
Configuration configuration =
configurationAdmin.createFactoryConfiguration(WALL_PID, bundleLocation);
configuration.update();
Dictionary wallProps = configuration.getProperties();
wallProps.put("x", x);
wallProps.put("y", y);
wallProps.put("z", z);
wallProps.put("length", length);
wallProps.put("height", height);
wallProps.put("rotate", rotate);
configuration.update(wallProps);
} catch (IOException e) {
e.printStackTrace();
}
}
view raw gistfile1.java hosted with ❤ by GitHub

In end I found out, that the two OSGi frameworks has the same configuration area, the same local directory. Provider an host are running on the same system. It was a coincidence that the fix work. If the PID for the configuration folder was not locked by the other OSGi instance everything works. So in the end I must say it is my mistake because the OSGi instances had the same directory configured as configuration area. But the design that the location depends on the first caller makes debugging crazy. Does anybody know if this is the expected behavior? This is really hard to debug, that the directory where the configuration is stored could depend on the first caller. What is the best practice set the location parameter always?

Freitag, 8. Juni 2012

Groovy Closures and Annotation Parameters

Since Groovy 1.8 there is support to have a closure as a parameter in annotations. A nice example how to use this feature is the GContracts project, a groovy design by contract framework, which use closure annotation parameters, to define pre and post conditions of a method.

The support of closures in annotations provides a simple way to have much more dynamic in annotations. This is cool and provides new areas where you now could use annotations. Here a simple example how a closure as annotation parameter could be used to group properties.

import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
@Retention(RetentionPolicy.RUNTIME)
@interface Parameter {
Class group()
}
class Group {
final String name
Group(String name){
this.name = name
}
String toString() {
name
}
}
class Data {
def nameGroup = new Group('names')
@Parameter(group={nameGroup})
String lastname
@Parameter(group={nameGroup})
String firstname
def addressGroup = new Group('address')
@Parameter(group={addressGroup})
String street
@Parameter(group={addressGroup})
String location
}
def data = new Data()
data.properties.each {property ->
Data.class.declaredFields.find { field ->
if(field.name == property.key &&
Parameter in field.declaredAnnotations*.annotationType()) {
def parameter = field.getAnnotation(Parameter)
def groupClosure = parameter.group().newInstance(data, data)
def group = groupClosure()
println "Property with name " + property.key +
" is in group " + group
}
}
}

More details about closures in annotation see the groovy 1.8 release notes.

Links:

Dienstag, 5. Juni 2012

Crazy Scala Combinator Parser

Updates
  • 2012-06-?? Add Chris Hodapp version to the post.
  • 2012-06-23 Fix word is now in the second sample no method anymore its a val
Create my first parser with the Scala combinator library. I really like the concept to have simple way to compose simple parsers via high-level functions to a complex parser. But I think the syntax for the internal Scala parser DSL is a little bit crazy. I’m not sure why the method names in Scala always must be as short as possible e.g. rep. For me this makes the source of my simple parser really crazy. Here my first simple key value parser to show how the source of Scala parser looks like.

import scala.util.parsing.combinator.RegexParsers
import scala.collection.immutable.Map
import scala.util.parsing.combinator.PackratParsers
/**
* Simple parser for a key value string like:
* key01 = Value01 key02=value02 key03 =value03 key04= value04
*
* The parser does not support whitespace in key or values.
*/
object KeyValueParser extends RegexParsers {
val emptyMap = Map[String, String]()
def keyValues = rep(keyValue) ^^ {
_.foldLeft(emptyMap)((map , pair) => map ++ Map(pair._1 -> pair._2))
}
def keyValue = key ~ value ^^ {
case key ~ value => (key, value)
}
def key = value ~ eq ^^ {
case key ~ eq => key.toString
}
def value = whitespace ~ word ~ whitespace ^^ {
case _ ~ word ~ _ => word.toString
}
def eq = "=".r
def word = "\\w+".r
def whitespace = "\\s*".r
/**
* Parse a key value text into a Map[String, String].
*/
def parse(input: String) = parseAll(keyValues, input) match {
case Success(result,_) => result
case failure : NoSuccess => throw new Exception(failure.msg)
}
}

The concept behind the Scala combinator parsers are great, try it and you will learn a lot about how to create a parser in functional language. But I don’t understand why always the shortest and cryptic methods names are used in Scala. This type of naming makes the source hard to read and understand and it makes the Scala source so crazy. But when you know the cryptic names it makes a lot of fun to write such crazy Scala source.

Try it more details about regex parsers please see the Scala doc. The demo parser is not perfect and I’m not a Scala professional, if there are any comments feel free write me how to make it better.

A better Scala version of the parser by Chris Hodapp here:
import scala.util.parsing.combinator.RegexParsers
/**
* Simple parser for a key value string like:
* key01 = Value01 key02=value02 key03 =value03 key04= value04
*
* The parser does not support whitespace in key or values.
*/
object KeyValueParser extends RegexParsers {
def map = rep(mapping) ^^ {_.toMap}
def mapping = word ~ "=" ~ word ^^ {
case key ~ _ ~ value => key -> value
}
val word = "\\w+".r
/**
* Parse a key value text into a Map[String, String].
*/
def parse(input: String) = parseAll(map, input) match {
case Success(result,_) => result
case failure : NoSuccess => throw new Exception(failure.msg)
}
}
Links

Groovy Declared Fields Filter Synthetic

Groovy generates some "synthetic" field to a class, that means the reflection method getDeclaredFields returns more fields than fields which are declared in the Groovy source of a class. To filter the "synthetic" fields the Groovy grep method could be used e.g. "anyClass. declaredFields.grep { !it.synthetic }".

import org.junit.Test
class DeclaredFieldsTest
{
static {
Class.metaClass.getNonSyntheticFields = { ->
delegate.declaredFields.grep { !it.synthetic }
}
}
class Data {
public String name
public int count
static def field(name) { Data.class.getField(name) }
}
@Test void getDeclaredFields() {
def expectedFields = [Data.field('name'), Data.field('count')]
assert expectedFields == Data.class.nonSyntheticFields
}
}
Links

Sonntag, 20. Mai 2012

Grails and Spring @Async Annotation

If some logic e.g. in a grails service should be invoked asynchronous, in Grails 2 the spring annotation @Async can be used. For that the spring annotation driven task support must be activated in the spring configuration. To activate the task support, the task namespace should be added to the spring configuration. Here a sample spring configuration ("resources.groovy").

beans = {
xmlns task:"http://www.springframework.org/schema/task"
task.'annotation-driven'('proxy-target-class':true, 'mode':'proxy')
}

Now the spring annotation can be used to mark e.g. service logic which should be invoked asynchronous. Here a sample to send mails asynchronous (for sending the mails the grails mail plugin is used).

import org.springframework.scheduling.annotation.Async
class NotificationService
{
def mailService
@Async
void notifyNewSigner(Signer signer)
{
mailService.sendMail {
subject "Demo Mail"
body(view: "/mail/signerRequest",
plugin: "email-confirmation",
model: [signer: signer])
}
}
}


For more details see also the spring framework documentation:
http://static.springsource.org/spring/docs/current/spring-framework-reference/html/scheduling.html#scheduling-annotation-support-async

Montag, 5. März 2012

Start buggy lazy Bundles

Yesterday I push to github a simple bundle, which I use in bnd and bndtools to activate buggy lazy bundles.

What is a buggy lazy Bundle?
Sometimes I have bundles with a Bundle-ActivationPolicy header, which is set to lazy. But no other bundle in the application loads classes from this bundle or use a service e.g. via DS from this bundle. In some cases the lazy bundle didn’t export anything.

When you like to use such lazy bundles, then this bundle must be start by hand. Examples are the Eclipse  ECF bundles. To use the ECF bundles (see also ticket ID-373475) some of the bundles must be start by hand because of the Bundle-ActivationPolicy header lazy. I think these are buggy bundles and the Bundle-ActivationPolicy header should be removed from the manifests.

When you use lazy bundles then this bundles should automatically started by the OSGi framework, when some other bundle in the application need the functionally of the lazy bundle. Think about before you use the Bundle-ActivationPolicy lazy. Only use lazy bundles when the OSGi framework could detect that some other bundle would like to use functionally which the lazy bundle provides.

Examples use lazy bundles when the bundle exports packages with classes and only when some other bundle loads a class from these exported packages the bundle should be in state active. Or when the bundle provides an OSGi service via DS and the bundle should only be in state active when some other bundle would like to use this service. So be careful with using the Bundle-ActivationPolicy header.

More about lazy activation bundle see the OSGi Alliance web site here.

Handling buggy lazy Bundles in Bnd
When you like to use a buggy lazy bundle with bnd or bndtools the bundle must be started by hand. For this I create a simple bundle, which I call “Start lazy Bundles”. The bundle implements an extender pattern which watch for starting bundles. When the starting bundle has a Bundle-ActivationPolicy lazy and the bundle symbolic name is set in a system property the “Start lazy Bundles” bundle try’s to start the bundle.

More details see the Github project:
https://github.com/tux2323/Start-lazy-Bundles

Freitag, 17. Februar 2012

Lambdaj Closure in Java

Yesterday we played around with the Lambdaj project. The project provides a fancy way to simulate closure in Java. Here some simple examples based on the lambda4j documentation code.

import static ch.lambdaj.Lambda.*;
import static ch.lambdaj.collection.LambdaCollections.*;
import static org.hamcrest.Matchers.*;
import java.util.List;
import javax.swing.JLabel;
import ch.lambdaj.collection.*;
import ch.lambdaj.function.closure.*;
public class LambdaDemo {
public static void main(String[] args) {
// Simple lambda4j closure demo
JLabel label = new JLabel("Test Label Name");
Closure closure = closure(); {of(label).getText();}
System.out.println(closure.apply());
// Simple lambda4j collection demos
LambdaList<Person> list = with(new Person("Michael Jackson"), new Person("Bob"));
System.out.println(joinFrom(list).getName());
// Select elements from a collection
List<Person> select = select(list, having(on(Person.class).getName(), equalTo("Bob")));
System.out.println(joinFrom(select).getName());
// println each person to system.out
Closure1<Person> personClosure = closure(Person.class); {of(System.out).println(var(Person.class));}
personClosure.each(list);
}
static class Person
{
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
}
view raw LambdaDemo.java hosted with ❤ by GitHub


And here a second example with "delayedClosure", which shows how to read a file line by line with lambda4j.

import static ch.lambdaj.Lambda.*;
import java.io.*;
import ch.lambdaj.function.closure.*;
public class FileReaderDemo {
public static void main(String[] args) {
File file = new File(FileReaderDemo.class.getResource("/demo.txt").getFile());
FileReader reader = new FileReader(file);
reader.eachLine(); {
of(System.out).println(var(String.class));
}
}
public static class FileReader {
private final File file;
public FileReader(File file) {
this.file = file;
}
public void eachLine() {
delayedClosure(new DelayedClosure<Void>() {
@Override
public Void doWithClosure(Closure lineReader) {
BufferedReader reader = null;
try {
InputStream stream = new FileInputStream(file);
reader = new BufferedReader(new InputStreamReader(stream));
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
lineReader.apply(line);
}
} catch (IOException ioe) {
throw new RuntimeException("Error while reading file " + file, ioe);
} finally {
try {
if (reader != null) reader.close();
} catch (IOException ioe) {
throw new RuntimeException("Error while closing file reader", ioe);
}
}
return null;
}
});
}
}
}


More details about lambda4j please have a look at the project website:
http://code.google.com/p/lambdaj/

Montag, 23. Januar 2012

Eclipse Equinox ECF Unpack *pack.gz

If you downloading Eclipse ECF as a ZIP file, the plugins folder in the ZIP contains pack200 compressed JAR files. The pack200 compressed files ends with *.pack.gz. The ECF ZIP distribution contains the same content like a normal Eclipse P2 update site.


If you like to use Eclipse Equinix ECF bundles without P2 or Eclipse you must unpack the pack200 OSGi bundels. For that eclipse provides a tool called "org.eclipse.equinox.p2.jarprocessor". Here a small bash script to show how to extract the OSGi bundles from the pack200 files.

for file in *.gz; do
${JAVA_HOME}/java -jar ${ECLIPSE_HOME}/plugins/org.eclipse.equinox.p2.jarprocessor_1.0.200.v20110502-1955.jar -unpack "${file}";
done
view raw ecf-unpack.sh hosted with ❤ by GitHub


Links