Tag Archives: eclipse

Adding a JDK and sources to Eclipse on a Mac

I just downloaded Eclipse on my Mac after a good six months without needing it and had numerous issues using it. First, it wouldn’t start and gave the error message below.

Alert: The JVM shared library "/Library/Java/JavaVirtualMachines/1.7.0.jdk" does not contain the JNI_CreateJavaVM symbol.

I realised that the openjdk 1.7.0 package I’d installed must be somehow overriding or interfering with the 1.6.0 JDK that Apple installs by default. So I went into Applications > Utilities > Java Preferences. As soon as I opened that I was prompted by a message that said that in order to open Java Preferences I must install a Java 6 runtime and asked me if I would like to do so. I obviously said yes after which I reviewed the order of JDKs in Java Preferences which was correct.

I also removed the openjdk 1.7.0 package I’d installed earlier to prevent it from disrupting my work again by running the command below which removed this entry from Java Preferences.

sudo rm -rf /Library/Java/JavaVirtualMachines/1.7.0.jdk/

Next, as I created a Java project, I realised Eclipse was still operating with a JRE and unsurprisingly I couldn’t access the source code of the JDK libraries. To resolve both these issues at once I went into Eclipse > Preferences > Java > Installed JREs > Add and added the following path.

/Library/Java/JavaVirtualMachines/1.6.0_24-b07-334.jdk/Contents/Home

You’ll notice this path contains the essential src.jar. Then I went into Project > Properties > Java Build Path > Libraries, removed the existing JRE and added the new JDK. I was now able to open String.class and see the source and all was well.

Why is Java still such a nightmare on OS X after all this time? I really hope it improves with Java 8. Anyway, I wrote all this up in the hope that it helps others also struggling with such problems.

Oracle celebrates upcoming Java 7 release on video

Oracle recently celebrated the upcoming release of Java 7 with great pomp and show and subsequently made recordings of the event available as a series of videos available. If you haven’t already done so watch the videos in order below and read the blog post. There are also some thoughts on what’s upcoming in Java 8 in the final Q&A video.

It’s great to see Oracle engaging with the community to this extent and so publicly. This could have been just another release but I’m glad it received more publicity and visibility in this way, particularly, giving sub-project leads within Java 7 the recognition they deserve and the inspiration to carry on doing their great work I hope. I’ve also subscribed to the Oracle Java Magazine to see what it offers in due time.

Introducing Java 7: Moving Java Forward

Technical breakout sessions

In addition to the main presentation there were also smaller and more specialised technical breakout sessions as below.

Making Heads and Tails of Project Coin, Small Language Changes in JDK 7 (slides)

Divide and Conquer Parallelism with the Fork/Join Framework (slides)

The New File System API in JDK 7 (slides)

A Renaissance VM: One Platform, Many Languages (slides)

Meet the Experts: Q&A and Panel Discussion

Thoughts

A few thoughts that occurred to me having watched the above presentations follow below.

  • In Joe’s presentation I realised just how important good editor support is to prompt developers to adopt the project coin proposals over older ways of achieving the same ends. I was very impressed watching Netbeans detecting older syntax, prompting the developer through providing helpful warnings and being able to change old to new syntax instantaneously. I really hope Eclipse does the same. Eclipse has asked for quick fix, refactoring and template suggestions and in response to that I would say the most important incorporations above supporting the language would be supporting idiomatic transitions from Java 6 and Java 7.
  • Watching Joe Darcy go through how they implemented switch on strings and the associated performance considerations was fascinating. They actually use the hashcode values of strings to generate offsets and then use the offsets to execute the logic in the original case statements.
  • I found it very cool that Stuart Marks actually retrofitted the existing JDK code to utilise some of the Project Coin features not by hand but in an automated fashion. Apparently the JDK team also used annotation based processing and netbeans based tooling to help them upgrade the JDK codebase to use the new features.

Eclipse AJDT intertypes and Push-In refactoring

In the wake of the recent 1.0.0 release of Spring Roo, while going through Ben Alex’s captivating three part tutorial (1,2,3) on the tool, I experienced one of those moments that are normally few and far between when you know you’ve come across something new – something rare and revolutionary for the space of technology that it’s acting within that would never have occurred to you – something lateral in nature (no pun intended as we’ll see later on). Meet Eclipse ADJT, intertypes and Push-In refactoring.

Let’s take the Spring Roo project in the above tutorial as an example.

Spring Roo Project

Spring Roo Project

Imagine the following pojo.

package name.dhruba.wedding.domain;

import javax.persistence.Entity;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.tostring.RooToString;
import org.springframework.roo.addon.entity.RooEntity;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.Date;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.springframework.format.annotation.DateTimeFormat;

@Entity
@RooJavaBean
@RooToString
@RooEntity(finders = { "findRsvpsByCodeEquals" })
public class Rsvp {

    @NotNull
    @Size(min = 1, max = 30)
    private String code;

    @Size(max = 30)
    private String email;

    private Integer attending;

    @Size(max = 100)
    private String specialRequests;

    @Temporal(TemporalType.TIMESTAMP)
    @DateTimeFormat(style = "S-")
    private Date confirmed;
    
    
}

It has no methods of any kind. Now imagine a separate compilation unit that provides these methods.

package name.dhruba.wedding.domain;

import java.lang.Integer;
import java.lang.Long;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.PersistenceContext;
import javax.persistence.Version;
import name.dhruba.wedding.domain.Rsvp;
import org.springframework.transaction.annotation.Transactional;

privileged aspect Rsvp_Roo_Entity {
    
    @PersistenceContext    
    transient EntityManager Rsvp.entityManager;    
    
    @Id    
    @GeneratedValue(strategy = GenerationType.AUTO)    
    @Column(name = "id")    
    private Long Rsvp.id;    
    
    @Version    
    @Column(name = "version")    
    private Integer Rsvp.version;    
    
    public Long Rsvp.getId() {    
        return this.id;        
    }    
    
    public void Rsvp.setId(Long id) {    
        this.id = id;        
    }    
    
    public Integer Rsvp.getVersion() {    
        return this.version;        
    }    
    
    public void Rsvp.setVersion(Integer version) {    
        this.version = version;        
    }    
    
    @Transactional    
    public void Rsvp.persist() {    
        if (this.entityManager == null) this.entityManager = entityManager();        
        this.entityManager.persist(this);        
    }    
    
    @Transactional    
    public void Rsvp.remove() {    
        if (this.entityManager == null) this.entityManager = entityManager();        
        if (this.entityManager.contains(this)) {        
            this.entityManager.remove(this);            
        } else {        
            Rsvp attached = this.entityManager.find(Rsvp.class, this.id);            
            this.entityManager.remove(attached);            
        }        
    }    
    
    @Transactional    
    public void Rsvp.flush() {    
        if (this.entityManager == null) this.entityManager = entityManager();        
        this.entityManager.flush();        
    }    
    
    @Transactional    
    public void Rsvp.merge() {    
        if (this.entityManager == null) this.entityManager = entityManager();        
        Rsvp merged = this.entityManager.merge(this);        
        this.entityManager.flush();        
        this.id = merged.getId();        
    }    
    
    public static final EntityManager Rsvp.entityManager() {    
        EntityManager em = new Rsvp().entityManager;        
        if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");        
        return em;        
    }    
    
    public static long Rsvp.countRsvps() {    
        return (Long) entityManager().createQuery("select count(o) from Rsvp o").getSingleResult();        
    }    
    
    public static List Rsvp.findAllRsvps() {    
        return entityManager().createQuery("select o from Rsvp o").getResultList();        
    }    
    
    public static Rsvp Rsvp.findRsvp(Long id) {    
        if (id == null) throw new IllegalArgumentException("An identifier is required to retrieve an instance of Rsvp");        
        return entityManager().find(Rsvp.class, id);        
    }    
    
    public static List Rsvp.findRsvpEntries(int firstResult, int maxResults) {    
        return entityManager().createQuery("select o from Rsvp o").setFirstResult(firstResult).setMaxResults(maxResults).getResultList();        
    }    
    
}

Imagine that your editor handles the separation seamlessly and merges the two for you to work with the API at compile time.

    @RequestMapping(method = RequestMethod.POST)
    public String post(@ModelAttribute("rsvp") Rsvp rsvp, ModelMap modelMap) {
        rsvp.setConfirmed(new Date());
        if (rsvp.getId() == null) {
            rsvp.persist();
        } else {
            rsvp.merge();
        }
        if (rsvp.getEmail().length() > 0) {
            sendMessage("Ben Alex ", "RSVP to our wedding", rsvp.getEmail(),
                    "Your RSVP has been saved: " + rsvp.toString());
        }
        modelMap.put("rsvp", rsvp);
        return "thanks";
    }

This allows Spring Roo to achieve a true separation of concerns as well a multitude of other compelling benefits.

Now imagine you want to merge such duality into one, project wide, once your initial project harness is ready. You can.

Right click the project » Refactor » Push-In.

Eclipse AJDT Push-In Menu

Eclipse AJDT Push-In Menu

Check pending actions.

Push-In pending actions

Push-In pending actions

Preview the action.

Preview Push-In Refactoring

Preview Push-In Refactoring

Apply and you can get the following outcome.

package name.dhruba.wedding.domain;

import javax.persistence.Entity;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.tostring.RooToString;
import org.springframework.roo.addon.entity.RooEntity;
import org.springframework.transaction.annotation.Transactional;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.Date;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Version;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.format.annotation.DateTimeFormat;

@Configurable
@Entity
@RooJavaBean
@RooToString
@RooEntity(finders = { "findRsvpsByCodeEquals" })
public class Rsvp {

    @NotNull
    @Size(min = 1, max = 30)
    private String code;

    @Size(max = 30)
    private String email;

    private Integer attending;

    @Size(max = 100)
    private String specialRequests;

    @Temporal(TemporalType.TIMESTAMP)
    @DateTimeFormat(style = "S-")
    private Date confirmed;
    
    

	public String toString() {    
        StringBuilder sb = new StringBuilder();        
        sb.append("Id: ").append(getId()).append(", ");        
        sb.append("Version: ").append(getVersion()).append(", ");        
        sb.append("Code: ").append(getCode()).append(", ");        
        sb.append("Email: ").append(getEmail()).append(", ");        
        sb.append("Attending: ").append(getAttending()).append(", ");        
        sb.append("SpecialRequests: ").append(getSpecialRequests()).append(", ");        
        sb.append("Confirmed: ").append(getConfirmed());        
        return sb.toString();        
    }

	@PersistenceContext    
    transient EntityManager entityManager;

	@Id    
    @GeneratedValue(strategy = GenerationType.AUTO)    
    @Column(name = "id")    
    private Long id;

	@Version    
    @Column(name = "version")    
    private Integer version;

	public Long getId() {    
        return this.id;        
    }

	public void setId(Long id) {    
        this.id = id;        
    }

	public Integer getVersion() {    
        return this.version;        
    }

	public void setVersion(Integer version) {    
        this.version = version;        
    }

	@Transactional    
    public void persist() {    
        if (this.entityManager == null) this.entityManager = entityManager();        
        this.entityManager.persist(this);        
    }

	@Transactional    
    public void remove() {    
        if (this.entityManager == null) this.entityManager = entityManager();        
        if (this.entityManager.contains(this)) {        
            this.entityManager.remove(this);            
        } else {        
            Rsvp attached = this.entityManager.find(Rsvp.class, this.id);            
            this.entityManager.remove(attached);            
        }        
    }

	@Transactional    
    public void flush() {    
        if (this.entityManager == null) this.entityManager = entityManager();        
        this.entityManager.flush();        
    }

	@Transactional    
    public void merge() {    
        if (this.entityManager == null) this.entityManager = entityManager();        
        Rsvp merged = this.entityManager.merge(this);        
        this.entityManager.flush();        
        this.id = merged.getId();        
    }

	public static final EntityManager entityManager() {    
        EntityManager em = new Rsvp().entityManager;        
        if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");        
        return em;        
    }

	public static long countRsvps() {    
        return (Long) entityManager().createQuery("select count(o) from Rsvp o").getSingleResult();        
    }

	public static List findAllRsvps() {    
        return entityManager().createQuery("select o from Rsvp o").getResultList();        
    }

	public static Rsvp findRsvp(Long id) {    
        if (id == null) throw new IllegalArgumentException("An identifier is required to retrieve an instance of Rsvp");        
        return entityManager().find(Rsvp.class, id);        
    }

	public static List findRsvpEntries(int firstResult, int maxResults) {    
        return entityManager().createQuery("select o from Rsvp o").setFirstResult(firstResult).setMaxResults(maxResults).getResultList();        
    }

	public String getCode() {    
        return this.code;        
    }

	public void setCode(String code) {    
        this.code = code;        
    }

	public String getEmail() {    
        return this.email;        
    }

	public void setEmail(String email) {    
        this.email = email;        
    }

	public Integer getAttending() {    
        return this.attending;        
    }

	public void setAttending(Integer attending) {    
        this.attending = attending;        
    }

	public String getSpecialRequests() {    
        return this.specialRequests;        
    }

	public void setSpecialRequests(String specialRequests) {    
        this.specialRequests = specialRequests;        
    }

	public Date getConfirmed() {    
        return this.confirmed;        
    }

	public void setConfirmed(Date confirmed) {    
        this.confirmed = confirmed;        
    }

	public static Query findRsvpsByCodeEquals(String code) {    
        if (code == null || code.length() == 0) throw new IllegalArgumentException("The code argument is required");        
        EntityManager em = Rsvp.entityManager();        
        Query q = em.createQuery("SELECT Rsvp FROM Rsvp AS rsvp WHERE rsvp.code = :code");        
        q.setParameter("code", code);        
        return q;        
    }
}

If we look at the difference in the number of files before and after you can clearly see the intertypes have been deleted.

$ find wedding.original/ | wc -l
     211
$ find wedding/ | wc -l
     191

Simply genius.

Support is upcoming for the opposite: Pull-Out.

Note that in order for the above to work you must either have STS which comes with the AJDT plugin or Eclipse with the AJDT plugin installed. Also you must either have the AspectJ nature or AJDT weaving enabled or both.

Spring Integration Series – Getting started

In the past few months I’ve had the good fortune of getting familiar in depth with Spring Integration and being responsible for adopting it for use within a major investment bank. I’ve learnt a lot through many different channels, met in person with people from SpringSource and those directly contributing to Spring Integration and provided my own feedback through all these channels derived from my experiences in using it to fulfil my commercial use-cases.

During all this time I’ve been dying to blog about Spring Integration and particularly my use of it but haven’t been able to due to lack of time and energy outside of work. Going forward, however, my hope is that I’ll write a series of articles, one at a time, each exploring a different perspective on Spring Integration.

Here we begin by looking at how to get started with Spring Integration and how to get close to the source of the project using Eclipse IDE. The value of this will be felt most when browsing the org.springframework.integration.samples project which contains numerous fully working examples of how to use Spring Integration in different ways.

Getting started

My approach to learning any new subject is to put theory first. Here’s what I did to get started.

  1. Read the manual (yes the entire ~100 pages).
  2. Set up the source (as in the next section of this article).
  3. Review the sample applications (once you’ve set up the source).

If you prefer a more pragmatic approach from the start you can dive straight into the sample applications and start to write your own by referring to the manual as and when needed but this approach has the danger of leaving gaps in your knowledge as you start to write code.

Getting close to the source

The tools that you’ll need to work with the source are as follows.

Here’s how to set up the Spring Integration source in Eclipse.

  1. Check out the source.
    svn co https://src.springframework.org/svn/spring-integration/trunk/ si
  2. Increase max perm size available to Ant.
    export ANT_OPTS="-XX:MaxPermSize=512m"
  3. Build the project. This will take approximately ten minutes while it downloads all dependencies using Ivy.

    cd si/build-spring-integration/

    ant

    If you are running on Ubuntu and at this point you get UnknownHostException error messages then see recommended fix.

  4. Import the project into eclipse.

    • File > Import > Existing projects into workspace
    • Select root directory > Browse > Select the si/ folder
    • Deselect the project with no name and click Finish
  5. Create an ivy cache variable as follows.

    • Right click on any of the projects you imported above.
    • Properties > Java Build Path > Libraries
    • Add Variable > Configure Variables > New
    • Enter variable name as ‘IVY_CACHE’ and value as something similar to /home/dhruba/sources/si/ivy-cache/repository
    • Confirm all the dialogue boxes. The projects should automatically rebuild.

At this point you should have all the Spring Integration projects imported into Eclipse with no fatal errors and at the time of writing 94 warnings. Common guys we can reduce that to zero 😉 Now you should be able to open up the org.springframework.integration.samples project and browse through and run the sample applications provided for you.

With any luck a number of further articles on Spring Integration should follow. I have a lot that I want to convey but it is, as always, finding the time and the energy to write not only the articles but fully working illustrative showcase applications.

Thanks to Jonas Partner, Spring Integration committer, for providing the instructions.