Stacktrace

Sida 2/21:123451020...21

Efter att du har läst Martins artikel om Scala och SBT så kanske du känner dig lite sugen att börja koda i Scala, men inte riktigt vet var du skall börja. Jonas Bonér var hos Cygni och talade för ett tag sedan och nämnde då att det kan vara en bra början att skriva sina testfall i Scala för att komma igång och lära sig språket. Scala erbjuder dessutom väldigt trevliga testramverk, som kan underlätta din vardag. Jag kommer förutsätta att du idag har ett mavenprojekt med javakod och eventuella befintliga tester i java.

Första steget är att lyfta in Scalas API, JUnit 4 (om du inte redan kör det) och ett testramverk. Jag tänkte använda ScalaTest. För att göra det så lägger vi till följande beroende i pom.xml

<dependency>
    <groupId>org.scala-lang</groupId>
    <artifactId>scala-library</artifactId>
    <version>2.9.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.8.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.scalatest</groupId>
    <artifactId>scalatest_2.9.1</artifactId>
    <version>1.6.1</version>
    <scope>test</scope>
</dependency>

Sedan behöver vi säga till Maven att också kompilera och köra testfall som ligger i biblioteket src/test/scala, så då lägger vi till tre plugins.

maven-scala-plugin ansvarar för att kompilera scalakoden till bytekod.

<plugin>
    <groupId>org.scala-tools</groupId>
    <artifactId>maven-scala-plugin</artifactId>
    <version>2.15.0</version>
    <executions>
        <execution>
            <goals>
                <goal>testCompile</goal>
            </goals>
            <configuration>
                <args>
                    <arg>-make:transitivenocp</arg>
                    <arg>-dependencyfile</arg>
                    <arg>${project.build.directory}/.scala_dependencies</arg>
                </args>
            </configuration>
        </execution>
    </executions>
</plugin>

maven-surefire-plugin är den som kör testerna – om du redan har tester i projektet så har du redan lagt till den här pluginen och behöver då bara utöka den att också inkludera filer som heter **/*Spec.*.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.6</version>
    <configuration>
        <useFile>false</useFile>
        <disableXmlReport>true</disableXmlReport>
        <includes>
            <include>**/*Spec.*</include>
            <!-- För att hantera existerande tester -->
            <include>**/*Test.*</include>
        </includes>
    </configuration>
</plugin>

build-helper-maven-plugin lägger till källkodsmappar till kompilering, eftersom Maven från början bara hanterar en källkodsmapp för implementationskod (src/main/java som standard) och en för test (src/test/java som standard).

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>build-helper-maven-plugin</artifactId>
    <executions>
        <execution>
            <id>generate-test-sources</id>
            <phase>generate-test-sources</phase>
            <goals>
                <goal>add-test-source</goal>
            </goals>
            <configuration>
                <sources>
                    <source>src/test/scala</source>
                </sources>
            </configuration>
        </execution>
    </executions>
</plugin>

Ok, nu behöver vi bara skapa mappen src/test/scala och sedan kan du börja koda!

Om du vill kan du stanna här. Nu kan du skriva testklasser i Scala, annotera metoderna med JUnits @Test och köra på som vanligt. Det du vinner är att du får tillgång till Scalas syntax och konstruktioner och att du kan lära dig i en bekant miljö.

Det andra alternativet är att du också börjar titta på vad Scalas testramverk kan erbjuda. I grunden är det inte så stor skillnad, men rent syntatiskt och kanske också tankemässigt så är det lite annorlunda. ScalaTest har stöd för BDD – Behaviour Driven Development. Tanken är att varje test är en beskrivning av en funktion/ett beteende som en roll skall uppfylla. Rollen tar sedan formen av en eller möjligtvis flera klasser. Tack vare att Scalas syntax går att det skriva ganska koncisa specifikationer, nästan som rena texttester för att beskriva beteendet som förväntas.

Vi börjar med att skriva en första specifikation, som vår applikation skall uppfylla.

@RunWith(classOf[JUnitRunner])
class MyApplicationSpec extends FlatSpec with MustMatchers {

  "My application" must "convert a string to hex values" in {
  }

}

Det här är ett komplett test, även om det inte gör något just nu – kroppen på specifikationen är tom. Om jag vill kan jag lämna det tomt och fylla på senare, eller så gör jag det lite tydligare att jag inte är klar med testet. Då skriver vi om det såhär

@RunWith(classOf[JUnitRunner])
class MyApplicationSpec extends FlatSpec with MustMatchers {

  "My application" must "convert a string to hex values" in (pending)

}

Väldigt tydligt och förklarande, eller hur? Ponera att jag skapar en klass som kan konvertera en sträng till hexadecimala värden (wow!). Då kan testkoden se ut som följande

@RunWith(classOf[JUnitRunner])
class MyApplicationSpec extends FlatSpec with MustMatchers {

  "My application" must "convert a string to hex values" in {
    val app = new MyApplication()
    app.convert("The donkey makes a left turn. I observe.") must equal ("54686520646f6e6b6579206d616b65732061206c656674207475726e2e2049206f6273657276652e")
  }

}

Klassen MyApplication är fortfarande skriven i Java, men jag testar den från Scala. Nyckelordet ”must” kommer från en trait i ScalaTest som heter MustMatchers. Det går också att använda ShouldMatchers, enda skillnaden är terminologin – must eller should, vilket du tycker om bäst.

Genom att fylla på med test av det här slaget så får du en ganska tydligt dokumentation vad du faktiskt förväntar dig av dina roller/klasser. Då slipper du en massa kommentarer i koden och/eller testmetoder som döpts ”testShouldConvertStringToHexValue” eller liknande. Enkelt och snyggt!

Vill du använda mockobjekt i din scalakod så kan du antingen köra på någon av de vanliga javabiblioteken (JMock, EasyMock, Mockito), eller så kan du prova Borachio som är skrivet i Scala.

Logback, ett ramverk för loggning på Java-plattformen, släpptes nyligen som version 1.0. Initiativtagare är personen bakom log4j och SLF4J, Ceki Gülcü. Logback bygger på log4j och kan därför ses som en direkt uppföljare. Logback kommer med inbyggt stöd för SLF4J för att underlätta byte av implementation av ramverk. Några av fördelarna över log4j som sägs vara högre prestanda, utökad testsvit för bättre tillförlitlighet, förbättrad automatisk omladdning av konfigurationsfiler, mer avancerade filter och integration med servlet-containers för loggning av http-access.

För att testa Logback, lägg till följande maven-beroende:

<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>1.0.0</version>
</dependency>

Logback-classic beror på logback-core och SLF4J och därför kommer dessa automatiskt inkluderas i projektet. Därefter är det bara att logga på samma sätt som med SLF4J:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...
Logger logger = LoggerFactory.getLogger(App.class);
logger.info("Hello World!");

Konfiguration påminner om log4j men skiljer sig på vissa punkter. Nedan är ett enkelt exempel på en Logback-konfiguration:

<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="3 seconds">

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{32} - %msg%n</pattern>
        </encoder>
    </appender>

    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logFile.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logFile.%d{yyyy-MM-dd_HH-mm}.log.zip</fileNamePattern>
            <maxHistory>5</maxHistory>
        </rollingPolicy>

        <encoder>
            <pattern>%-26(%d{HH:mm:ss,SSS} [%thread]) %-5level %logger{32} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="DEBUG">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="FILE" />
    </root>

</configuration>

Här beskriver jag hur man snabbt och enkelt kan sätta upp en jee-applikation (ear, webapp- och ejb-modul) på några få minuter genom att använda sig av Maven-arketyper ifrån org.codehaus.mojo.archetypes och kommandot mvn archetype:generate. Vi tar också användning av eclipse m2e-plugin för att uppdatera beroenden mellan ear och web/ejb-modulerna.

För den som vill komma åt det som denna artikel producerar (finns lite mer godis också i form av enklare ejb och servlet-klasser) så finns den tillgänglig på github:
git clone http://github.com/cygni-stacktrace/j2ee-maven-5minutes

Generera jee-arketyper

Ställ dig i lämplig katalog för att påbörja skapandet av vårt projekt. Första gången vi kör mvn archetype:generate (ska köras sammanlagt 3 ggr) letar vi upp och anger siffran för codehause-arketypen ear-javaee6. För varje gång vi kör kommandot ser infon ungefär likadan ut.

EAR-input:

Define value for property ‘groupId’: : se.cygni.stacktrace.myearproject
Define value for property ‘artifactId’: : my-ear
Define value for property ‘version’:  1.0-SNAPSHOT: :
Define value for property ‘package’:  se.cygni.stacktrace.mywebexample: : ear

Andra gången anger vi siffran för arketypen webapp-javaee6. Input:

Define value for property ‘groupId’: : se.cygni.stacktrace.mywebexample
Define value for property ‘artifactId’: : my-web
Define value for property ‘version’: 1.0-SNAPSHOT: :
Define value for property ‘package’: se.cygni.stacktrace.mywebexample: : war

Tredje gången anger vi siffran för arketypen ejb-javaee6. Input:

Define value for property ‘groupId’: : se.cygni.stacktrace.myejbexample
Define value for property ‘artifactId’: : my-ejb
Define value for property ‘version’:  1.0-SNAPSHOT: :
Define value for property ‘package’:  se.cygni.stacktrace.myejbexample: : ejb

När vi är klara med det här kommer det finnas tre kataloger, my-ear, my-web och my-ejb med varsin pom.xml som har en hyfsat bra grunduppsättning av JEE-beroenden uppsatta från början.

Skapa en parent-pom

För att bland annat kunna bygga hela vår applikation i ett svep kopplar vi ihop dessa my-ear/my-web och my-ejb pom.xml till en och samma parent pom.xml. Skapa manuellt katalogen my-app på samma nivå som de andra katalogerna och en pom.xml fil med bland annat följande (hela my-app/pom.xml kan hittas här):

<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>se.cygni.stacktrace</groupId>
  <artifactId>my-app</artifactId>
  <packaging>pom</packaging>
  <version>1.0</version>
  <name>my-app</name>

  <modules>
  	<module>../my-ear</module>
  	<module>../my-web</module>
  	<module>../my-ejb</module>
  </modules>
...

I samband med att vi gör det här så tar vi också bort Version-taggen och sätter parent att vara my-app i pom.xml i my-web, my-ejb och my-ear. Hur alla pom.xml ser ut efter detta kan ses: här.

Nu kan vi nerifrån och upp genom ett kommando bygga web, ejb samt ear. Ställ dig bara i my-app och kör mvn package!

Modifiera ear att innehålla web och ejb-beroenden

Nu kör vi igång eclipse och tar hjälp av de verktyg som finns där för att sätta våra beroende mellan ear och ejb/web-modulerna. En förutsättning är att du har m2e-pluginen installerad i eclipse. Plocka den härifrån http://download.eclipse.org/technology/m2e/releases/ och när det är gjort så importerar du pom.xml i my-app-katalogen in i eclipse (File-> Import -> Maven -> Existing Maven Projects). Det kommer skapa 4 olika projekt i eclipse, my-app, my-ear, my-web och my-ejb.

Öppna upp my-ear/pom.xml och modifiera stycket:

 <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-ear-plugin</artifactId>
        <version>2.6</version>
        <configuration>
            <version>6</version>
            <defaultLibBundleDir>lib</defaultLibBundleDir>
        </configuration>
      </plugin>

till:

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-ear-plugin</artifactId>
				<version>2.6</version>
				<configuration>
					<version>6</version>
					<defaultLibBundleDir>lib</defaultLibBundleDir>
					<modules>
						<ejbModule>
							<groupId>se.cygni.stacktrace.myejbexample</groupId>
							<artifactId>my-ejb</artifactId>
						</ejbModule>
						<webModule>
							<groupId>se.cygni.stacktrace.mywebexample</groupId>
							<artifactId>my-web</artifactId>
						</webModule>
					</modules>
				</configuration>
			</plugin>

Sen högerklickar du på my-ear-projektet i package explorer och väljer Maven -> Add dependency. I sökrutan anger du ”my-ejb”, då kommer ditt ejb-projekt att dyka upp och du väljer detta och klickar OK. Upprepa proceduren för my-web projektet. Din my-ear/pom.xml bör nu innehålla detta:

	<dependencies>
		<dependency>
			<groupId>se.cygni.stacktrace.mywebexample</groupId>
			<artifactId>my-web</artifactId>
			<version>1.0</version>
			<type>war</type>
		</dependency>
		<dependency>
			<groupId>se.cygni.stacktrace.myejbexample</groupId>
			<artifactId>my-ejb</artifactId>
			<version>1.0</version>
			<type>ejb</type>
		</dependency>
	</dependencies>

Efter det här kan man roa sig med att städa upp ytterligare i sina pom.xml filer genom att t.ex se till att maven-compiler-plugin bara finns i my-app/pom.xml med rätt version etc. Men i princip är din grundstruktur nu klar och du kan ställa dig i my-app och köra mvn package för att få en fin ear-fil som kan deployas på en jee6-kompatibel app-server.

Idag tillhör det vanligheterna att du som utvecklare skriver automatiska test för din kod. Många projekt använder sig av olika former av dependency injection eller har beroenden mellan klasser som gör det krångligt att testa varje del för sig. Detta leder ibland till att tester omfattar stora delar att systemet (mer åt integrationstestning), vilket i sin tur leder till att det blir krångligt att underhålla och svårt att felsöka. Vissa framhåller att större tester gör dem robusta – de går inte ”sönder” lika lätt om något ändras inne i implementationen – men jag föredrar en robust implementation framför ett robust test, om ni förstår vad jag menar. Ju mindre del som varje test måste verifiera desto bättre – själva grunden för enhetstestning.

Hur bryter du isär koden så att det går att testa separat då? Jo, här kommer då mockobjekt in i bilden. Med hjälp av dessa syntetiska objekt som representerar dina kodberoenden så kan du isolera den kod som du vill testa, utan att råka ut för NullPointerException. Termen myntades (iallafall för den bredare publiken) av några utvecklare på en extreme-programming-konferens år 2000, där de också presenterade ett första ramverk för detta.

Ponera följande kodexempel (där Courier är ett interface)

class AwesomeApp {
   Courier courier;
   public Content checkPacket() {
      if ( !courier.hasNewPacket() ) {
         throw new NoNewPacketAsFarAsWeCouldSeeException();
      }
      Packet packet = courier.getNewPacket();
      Content content = packet.open();
      return content;
   }
   public void setCourier(Courier courier) {
      this.courier = courier;
   }
}

Om jag skriver följande test, så ramlar jag oundvikligen ned i NullPointerException-gropen eftersom courier är null i AwesomeApp.

class AwesomeAppTest {
   public void testCheckPacket() {
     AwesomeApp app = new AwesomeApp();
     Content content = app.checkPacket();
     // Assert content
   }
}

Vad göra? Lösningen är då alltså att använda ett mockobjekt. Antingen kan jag skriva en egen klass som implementerar interfacet Courier, samt hantera alla testvillkor som objekt av den klassen måste uppfylla, eller så använder jag ett färdigt ramverk. Valet känns lätt. Genom att välja ett färdigt ramverk så slipper jag en del underhåll och får samtidigt ett färdigt utvecklingsmönster att följa – annars kan det lätt bli att varje utvecklare i ett projekt gör på sitt eget sätt.

De vanligaste ramverken som används idag skulle jag säga är EasyMock, JMock samt Mockito. De är alla likvärdiga i funktionalitet och även om konstruktionerna kan skilja sig lite åt så är grunden densamma. Jag har också stött på ett ramverk som heter RMock, men det är gammalt och stöder inte ens Java 5 Generics, så jag tar inte upp det här. Här nedan följer några exempel på hur AwesomeAppTest skulle skrivas med alla tre ramverken, så att läsaren kan jämföra.

JMock

JMock har funnits länge och är en vidareutveckling av det ramverk som presenterades på extreme-programming-konferensen jag nämnde ovan. Version 1 var lite knölig att använda, eftersom metodmatchning gjordes med strängar vilket gav problem vid refaktorisering. Detta är dock löst i version 2 som sedan länge är den som gäller.

class AwesomeAppTest {
   @Test
   public void testCheckPacket() {
      // JMock-specifik klass
      Mockery mockery = new Mockery();
      // Här skapar vi vårt mockobjekt med JMock
      Courier courier = mockery.mock(Courier.class);

      // Förväntat returvärde från testade koden
      Content expectedContent = new Content();
      // Returvärden från mitt mockobjekt
      Packet anyPacket = new Packet(expectedContent); 

      // Definiera våra förväntningar, ett anrop till
      // courier.hasNewPacket() och ett till
      // courier.getNewPacket() samt deras returvärden
      mockery.checking(new Expectations() {{  

         oneOf(courier).hasNewPacket();
         will(returnValue(true));

         oneOf(courier).getNewPacket();
         will(returnValue(anyPacket)); 

      }});

      AwesomeApp app = new AwesomeApp();
      // Här sätter vi vårt mockobjekt som
      // beroende till AwesomeApp
      app.setCourier(courier);
      Content content = app.checkPacket();

      // Kontrollera att resultatet är det förväntade
      assert content == expectedContent;

      // Verifiera att förväntningarna inträffade
      mockery.assertIsSatisfied(); 

   }
}

EasyMock

EasyMock är också ganska gammal i gemet och var tidig med att ha stöd för refaktorisering.

class AwesomeAppTest {
   @Test
   public void testCheckPacket() {
      // Här skapar vi vårt mockobjekt med hjälp av EasyMock
      Courier courier = EasyMock.createMock(Courier.class); 

      // Förväntat returvärde från testade koden
      Content expectedContent = new Content();
      // Returvärden från mitt mockobjekt
      Packet anyPacket = new Packet(expectedContent); 

      // Definiera våra förväntningar, ett anrop till
      // courier.hasNewPacket() och ett till
      // courier.getNewPacket()  samt deras returvärden
      EasyMock.expect(courier.hasNewPacket()).andReturn(true);
      EasyMock.expect(courier.getNewPacket()).andReturn(anyPacket);

      // Sätt EasyMock i replay-läge,
      // där förväntningarna skall uppfyllas
      EasyMock.replay(courier); 

      AwesomeApp app = new AwesomeApp();
      // Här sätter vi vårt mockobjekt som
      // beroende till AwesomeApp
      app.setCourier(courier);
      Content content = app.checkPacket();

      // Kontrollera att resultatet är det förväntade
      assert content == expectedContent;

      // Verifiera att förväntningarna inträffade
      EasyMock.verify(courier);
   }
}

Mockito

Mockito är i praktiken en vidareutveckling av EasyMock, från början en fork som nu har skrivits om helt. Tack vare arvet är dock syntaxen väldigt lik.

class AwesomeAppTest {
   @Test
   public void testCheckPacket() {
      // Här skapar vi vårt mockobjekt med hjälp av Mockito
      Courier courier = Mockito.mock(Courier.class); 

      // Förväntat returvärde från testade koden
      Content expectedContent = new Content();
      // Returvärden från mitt mockobjekt
      Packet anyPacket = new Packet(expectedContent); 

      // Definiera våra förväntningar, ett anrop till
      // courier.hasNewPacket() och ett till
      // courier.getNewPacket() samt deras returvärden
      Mockito.when(courier.hasNewPacket()).thenReturn(true);
      Mockito.when(courier.getNewPacket()).thenReturn(anyPacket);

      AwesomeApp app = new AwesomeApp();
      // Här sätter vi vårt mockobjekt som
      // beroende till AwesomeApp
      app.setCourier(courier);
      Content content = app.checkPacket();

      // Kontrollera att resultatet är det förväntade
      assert content == expectedContent;

      // Verifiera att förväntningarna inträffade
      Mockito.verify(courier);
   }
}

Summering

Som ni ser skiljer det inte mycket mellan ramverken, det som kanske framträder mest är att EasyMock har ett steg extra – där EasyMock sätts i ”replay”-läge – mot både JMock och Mockito. Alla tre har stöd för att verifiera att metodanrop sker i rätt ordning, verifiera argument etc. Det går också att sätta mjukare förväntningar, såsom att en metod skall anropas en eller flera gånger, att man inte bryr sig om anrop och returvärde på ett visst objekt osv.

Vilket ramverk du skall välja är mer upp till personlig smak än funktionalitet. I de flesta fall kanske du sitter i ett projekt som redan använder ett mockramverk och då har du förhoppningsvis fått en lite bättre förståelse för vad ramverket gör.

Som avslutning kan jag rekommendera lite läsning från utvecklarna som myntade begreppet mockobjekt. Du hittar det på www.mockobjects.com – läs gärna deras papper som ligger som länkar i högerkolumnen på den sidan.

Det är vanligt förekommande att utvecklare behöver skriva kod för att konvertera listor. Listor kan behöva filtreras eller konverteras mellan olika format. Ett vanligt förekommande mönster när en lista ska konverteras är att skapa en ny lista för resultatet, iterera över ett givet data-set, konvertera varje post och lägga det till resultat-listan. Det är inte helt ovanligt att resultatet också filtreras i denna process. Nedan är ett exempel i Java:

Collection<String> c = new ArrayList<String>();
for (Person person : persons) {
  if (person.getAge() >= 18) {
    c.add(person.getName());
  }
}

Ovanstående exempel kan tyckas både enkelt och funktionellt men jämför med hur detta kan lösas i Python:

l = [person.name for person in persons if person.age >= 18]

Alternativt genom att använda filter och lambda kan det också skrivas så här:

l = [person.name for person in filter(lambda person: person.gender >= 18, persons)]

I Java finns tyvärr inte motsvarande funktionalitet. Det finns däremot alternativ för att lösa det på ett liknande sätt. Guava är ett projekt och innehåller flera bibliotek som Google använder till sina Java-projekt. Bland annat erbjuder dessa bibliotek funktioner för att filtrera och transformera listor på ett mer ‘funktionellt’ sätt. Nedan är en lösning som löser samma problem som ovan implementerad med hjälp av dessa funktioner:

Function<Person, String> f = new Function<Person, String>() {
  @Override
  public String apply(Person input) {
    return input.getName();
  }
};

Predicate<Person> p = new Predicate<Person>() {
  @Override
  public boolean apply(Person input) {
    return input.getAge() >= 18;
  }
};

Collection<String> c = Collections2.transform(Collections2.filter(persons, p), f);

Enklare exempel som detta blir möjligtvis varken mer kompakta eller lättlästa. När konverteringar som denna däremot upprepas så blir detta alternativ genast mer attraktivt. Jämför till exempel med JDBC-mappers som inte helt sällan återanvänds. Guava är licensierat under Apache License 2.0 och innehåller flertalet användbara funktioner. Ett alternativ är också Apache Commons, värt att nämna är att Apache Commons för närvarande tyvärr inte stödjer Java generics.

Lägg till följande beroende i din Maven-pom för att testa Guava:

<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>10.0.1</version>
</dependency>

I väntan på en Java-version (Java 8?) som stödjer closures och lambda-funktioner går det också att använda lambdaj. Med lambdaj kan en lista till exempel konverteras och filtreras på följande sätt:

import static ch.lambdaj.Lambda.*;
import static org.hamcrest.Matchers.*;
...
Collection<String> c = collect(filter(having(on(Person.class).getAge(), greaterThanOrEqualTo(18)), persons), on(Person.class).getName());

Lägg till följande Maven-beroende för att använda lambdaj:

<dependency>
  <groupId>com.googlecode.lambdaj</groupId>
  <artifactId>lambdaj</artifactId>
  <version>2.3.1</version>
</dependency>

JRebel är ett trevligt utvecklingsverktyg som gör det möjligt att omedelbart testa ändringar i en applikation som körs utan att starta om applikationsservern (ex Tomcat, Jetty, Glassfish, JBoss, WebSphere etc). Denna JVM-plugin stödjer omladdning av allt från JPA-entiteter, Session beans, JSP:er till resurs- och konfigurationsfiler. Förändringar i klasshierarkier stöds dock inte för tillfället. Det finns plugins till de populäraste utvecklingsmiljöerna och flertalet Java-ramverk stöds.

JRebel kostar en slant men kan spara tid och effektivisera utvecklingsarbetet, framförallt när det gäller större och tyngre applikationer som tar lång tid att bygga och/eller deploya.

Läs mer om JRebel på http://www.zeroturnaround.com/jrebel/

I dagens utvecklingsklimat med smidiga, lättlärda ramverk för att bygga rika gränssnitt med JavaScript är det lätt att underskatta vikten av en förståelse för språket som t ex populära jQuery bygger på.

JavaScript är ett kraftfullt språk, och i nuläget ett av världens mest använda, och Douglas Crockford är den guru (eller mahatma som han själv titulerar sig) som axlat ansvaret att hjälpa världens webbutvecklare att bygga snabba, snygga webbapplikationer på rätt sätt.

I hans numera klassiker, ”Javascript – The Good Parts”, belyser han det bra jämte med det mindre bra i språket Mocha, som blev LiveScript, som blev JavaScript.

Exempelvis illustrerar han fall som t ex nedan där alla returnerar true:

'' == 0
0 == '0'
'' != '0'
NaN != NaN

Men också hur man strukturerar sin kod rätt, vad i språket som bör undvikas och mycket mer.

Utöver hans bok har mannen bakom b la JSON och JSLint givit ett flertal föreläsningar som alla är sevärda. Både bok och föreläsningar rekommenderas varmt för alla webbutvecklare, oavsett språk.

Tidigare idag fick jag tips från min kollega Mikael Elm om ramverket JSefa som de använder för att skapa fixed length records vid kommunikation med ett legacy-system.

JSefa är ett litet och smidigt ramverk för strömmande serialisering av javaobjekt till XML, CSV och FLR.

Nedanstående exempel visar FLR-användningen av JSefa

Objektet som ska serialiseras

@FlrDataType()
public class Person {
    @FlrField(pos = 1, length = 30)
    private String name;

    @FlrField(pos = 2, length = 10, format = "dd.MM.yyyy", align = Align.RIGHT)
    private Date birthDate;
}

Serialisering

Serializer serializer = FlrIOFactory.createFactory(Person.class).createSerializer();
StringWriter writer = new StringWriter();
serializer.open(writer);

// call serializer.write for every object to serialize...

serializer.close(true);

Resultatet blir då:

Erwin Schmidt                 23.05.1964
Thomas Stumm                  12.03.1979

Deserialisering

Deserializer deserializer = FlrIOFactory.createFactory(Person.class).createDeserializer();
StringReader reader = new StringReader(writer.toString());
deserializer.open(reader);
while (deserializer.hasNext()) {
    Person p = deserializer.next();
    // do something useful with it...
}
deserializer.close(true);

För att serialisera XML eller CSV används liknande konstruktioner med annotationer och Serializers/Deserializers.

Eclipse plockar per default det inloggade namnet och sätter i @author-taggen i all javadoc som man skriver. Jag personligen vill oftast att mitt riktiga namn skrivs där istället. Ett sätt att få till det är att man editerar code templates, Inställningar -> Java -> Code Style -> Code Templates. Detta känns ju inte helt optimalt så istället brukar jag editera eclipse.ini filen och lägga till följande fetmarkerade variabel:

-Xms256m

-Xmx1024m

-Duser.name=Anders Hedström

och vips så plockar Eclipse upp det värdet när jag skapar ny javadoc

Sida 2/21:123451020...21