Monday 10 August 2009

Install Eclipse UI Form Editor

Developing Swing (or any other GUI) forms can be cumbersome and time consuming especially if you're a newbie or have complex screens to build. Form editors such as NetBeans Matisse or Eclipse plugin Jigloo can help you speed up the development time by providing a simple drag and drop form building. In this article we’re not comparing the form builders and in no way I'm saying that the mentioned form builders are better than others.

This article shows you how to installed CloudGarden's Jigloo plugin for Eclipse Galileo 3.5. The contents can be used also as a guide on how to install and remove plugins from Eclipse. Note that different versions of Eclipse may use different dialogs and include different options.

It is assumed that the computer you’re installing the plugin is connected to the Internet and have access to the following URI: http://cloudgarden1.com/update-site.

Install Jigloo Plugin

Eclipse provides a framework for its plugins. This simplifies the installation and removal process of plugins such as Jigloo. Open Eclipse, if not already opened. To add a new plugin, open the Help menu and select the Install New Software... menu item.

Help -> Install New Software

The Install dialog will open from where you can add and install new plugins. Click on the Add... button to add a new site from where the plugin is downloaded and installed as shown in the following screenshot.

Add Site

Add the site details in the small dialog, titled Add Site, displayed. Enter a friendly name (it can be anything you like) and the location from where the plugin will be downloaded and installed. The location for Jigloo is: http://cloudgarden1.com/update-site.

Enter Site Details

Click OK to continue. As shown in the following screenshot, the new site may not be listed in the work with dropdown list.

Work With dropdown list (without the Jigloo site)

In this case, close the dialog and reopen it from the menu Help -> Install New Software... as described earlier (click here for details) for Eclipse to refresh the sites list. The new site will be displayed in the work with dropdown list. Select the Jigloo site and click Next to continue.

Work With dropdown list (with the Jigloo site)

Eclipse will list all available plugins from the selected site. Select the Jigloo GUI Builder and then click Next > to continue.

Add Jigloo

Wait for Eclipse to calculate the requirements and dependencies. When ready, Eclipse will list the installation details. Click Next > to continue. Read the license agreement and only proceed if you accept it. Eclipse will download the required files and installed these when ready.

Wait for Eclipse to Download and Install

When ready, a dialog will be displayed suggesting restart of Eclipse. Click Yes to restart Eclipse. Wait for Eclipse to restart.

Create a JFrame

The main focus of this article is to illustrate how to install and remove Eclipse plugin Jigloo. The following online tutorial: http://www.cloudgarden1.com/swing_tutorial/index.html provides detailed examples of how to use this plugin to create Swing based forms.

To create a new JFrame, we first need to create a new project (unless you have one created already). Create a project or select an existing one. Then press Ctrl+N simultaneously to open the New dialog. Expand the GUI Forms node, then the Swing node and select the JFrame option as shown below.

New JFrame

If the form is greyed out (disabled) that means that you have not selected a project. Make sure you either select an existing project or create a new one before you proceed.

Provide a package name and a name for the JFrame. Note that names in Java must start with a letter, underscore or a dollar sign. Numbers can be included but not as the first letter. Press Finish to complete the process.

Package and Frame names

Eclipse will open the new frame for editing. Components can be added and removed graphically in a drag and drop manner. For more about this, please refer to the tutorial: http://www.cloudgarden1.com/swing_tutorial/index.html

Eclipse

Uninstall the Plugin

To uninstall a plugin, open the Help menu and select About Eclipse menu item. The about dialog will be displayed.

Click on the Installation Details button. The Eclipse Installation Details dialog will open. With the Installed Software tab selected, select the Jigloo plugin and click Uninstall….

Uninstall

Wait for Eclipse to calculate the requirements and dependencies. Click Finish on the Uninstall dialog to confirm the uninstallation. Wait for Eclipse to finish the uninstallation and click Yes when prompting to restart.

Thursday 6 August 2009

Relations made simpler with JPA

One of the differences between rational databases and object oriented programming (OOP) is the way data elements are represented. To handle this difference, additional code (sometimes referred to as data access objects) that translates from records to objects and vice-versa has to be produced and maintained in order for an application to communicate with the database.

This article illustrates how JSR-220, or as better known Java Persistence API (JPA), can help reducing the amount of code and effort required to synchronise both worlds.

In order to complete the examples illustrated here, the following jar files have to be in the classpath: toplink-essentials.jar; toplink-essentials-agent.jar; and derby.jar. These can be downloaded from: Oracle Toplink JPA and JavaDB respectively. These examples can be executed on databases other than the JavaDB (formerly known as Derby). To execute them on other databases you need the appropriate JDBC jar file.

A simple address book application (with no graphical user interface) will be used to illustrate the examples discussed here. The application data is made from four classes: Address; Person; Contact; and Group. The following figure illustrates the relations between these classes.


Figure 1. Relation between Classes

The counter tables are illustrated in the following figure


Figure 2. Relation between Classes

The above relations are summarised below

  • One or more persons can be living in the same address
  • Persons can be grouped together
  • A person can be in more than one group
  • A person has a set of contacts (numbers, emails)
  • A person has a main contact
  • A contact cannot be shared between two persons

Note that even in a simple application like this, the number of classes and tables required to represent the data in the respective format are different. This adds to the complexity required to translate between both worlds.

Setting up the Database

The SetupDatabase class, listed below, can be used to setup the database referred to from this article. It first drops all foreign keys (using the alter command) and tables and then re-creates everything. The altering and dropping processes will produce errors when executed for the first time as the tables in question are not available. Finally it populates them with some default data. Run the SetupDatabase class twice to make sure that everything is in place. The second time round should produce no errors. Note that this class requires the jar file derby.jar (or the libraries of your database) in the classpath.

package x2x;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;

public class SetupDatabase {

  private static String[] buildDatabase = {
      "ALTER TABLE CONTACTS DROP CONSTRAINT CONTACT_PERSON_1",
      "ALTER TABLE PERSONS DROP CONSTRAINT PERSON_ADDRESS_1",
      "ALTER TABLE PERSONS DROP CONSTRAINT PERSON_CONTACT_1",
      "ALTER TABLE PERSONS_GROUPS DROP CONSTRAINT PERSON_GROUP_1",
      "ALTER TABLE PERSONS_GROUPS DROP CONSTRAINT PERSON_GROUP_2",

      "DROP TABLE ADDRESSES",
      "DROP TABLE CONTACTS",
      "DROP TABLE GROUPS",
      "DROP TABLE PERSONS_GROUPS",
      "DROP TABLE PERSONS",

      "CREATE TABLE ADDRESSES (ADDRESS_ID INTEGER NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY(START WITH 1, INCREMENT BY 1), ADDRESS VARCHAR(255) NOT NULL)",
      "CREATE TABLE CONTACTS (CONTACT_ID INTEGER NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY(START WITH 1, INCREMENT BY 1), CONTACT_TYPE VARCHAR(255) NOT NULL, CONTACT_VALUE VARCHAR(255) NOT NULL, PERSON_ID INTEGER NOT NULL)",
      "CREATE TABLE GROUPS (GROUP_ID INTEGER NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY(START WITH 1, INCREMENT BY 1), GROUP_NAME VARCHAR(255) NOT NULL)",
      "CREATE TABLE PERSONS (PERSON_ID INTEGER NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY(START WITH 1, INCREMENT BY 1), LAST_NAME VARCHAR(255) NOT NULL, FIRST_NAME VARCHAR(255) NOT NULL, ADDRESS_ID INTEGER NOT NULL, MAIN_CONTACT_ID INTEGER NOT NULL)",
      "CREATE TABLE PERSONS_GROUPS (GROUP_ID INTEGER NOT NULL, PERSON_ID INTEGER NOT NULL, PRIMARY KEY (GROUP_ID, PERSON_ID))",

      "INSERT INTO ADDRESSES (ADDRESS) VALUES ('123, Somewhere road, Some Place')",
      "INSERT INTO ADDRESSES (ADDRESS) VALUES ('456, Anywhere road, Another Place')",
      "INSERT INTO ADDRESSES (ADDRESS) VALUES ('789, Around the corner road, Near By Place')",
      "INSERT INTO ADDRESSES (ADDRESS) VALUES ('012, Up the Hill, Not far away Place')",

      "INSERT INTO CONTACTS (CONTACT_TYPE, CONTACT_VALUE, PERSON_ID) VALUES ('Phone (Work between 7 and 15)', '00112233', 1)",
      "INSERT INTO CONTACTS (CONTACT_TYPE, CONTACT_VALUE, PERSON_ID) VALUES ('Mobile (Work)', '99887766', 2)",
      "INSERT INTO CONTACTS (CONTACT_TYPE, CONTACT_VALUE, PERSON_ID) VALUES ('Fax (Work)', '23452345', 2)",
      "INSERT INTO CONTACTS (CONTACT_TYPE, CONTACT_VALUE, PERSON_ID) VALUES ('Email (Work)', 'peterwhite@somecompany.com', 1)",
      "INSERT INTO CONTACTS (CONTACT_TYPE, CONTACT_VALUE, PERSON_ID) VALUES ('Email (Personal)', 'marybrown@somefreemail.com', 4)",
      "INSERT INTO CONTACTS (CONTACT_TYPE, CONTACT_VALUE, PERSON_ID) VALUES ('Mobile (Personal)', '67678989', 5)",
      "INSERT INTO CONTACTS (CONTACT_TYPE, CONTACT_VALUE, PERSON_ID) VALUES ('Phone (Home)', '78784545', 3)",
      "INSERT INTO CONTACTS (CONTACT_TYPE, CONTACT_VALUE, PERSON_ID) VALUES ('Phone (Home)', '45453232', 2)",

      "INSERT INTO PERSONS (FIRST_NAME, LAST_NAME, ADDRESS_ID, MAIN_CONTACT_ID) VALUES ('Peter', 'White', 1, 4)",
      "INSERT INTO PERSONS (FIRST_NAME, LAST_NAME, ADDRESS_ID, MAIN_CONTACT_ID) VALUES ('John', 'Smith', 2, 2)",
      "INSERT INTO PERSONS (FIRST_NAME, LAST_NAME, ADDRESS_ID, MAIN_CONTACT_ID) VALUES ('Jane', 'Smith', 2, 7)",
      "INSERT INTO PERSONS (FIRST_NAME, LAST_NAME, ADDRESS_ID, MAIN_CONTACT_ID) VALUES ('Mary', 'Brown', 3, 5)",
      "INSERT INTO PERSONS (FIRST_NAME, LAST_NAME, ADDRESS_ID, MAIN_CONTACT_ID) VALUES ('Jack', 'Black', 4, 6)",

      "INSERT INTO GROUPS (GROUP_NAME) VALUES ('Family')",
      "INSERT INTO GROUPS (GROUP_NAME) VALUES ('Colleagues')",

      "INSERT INTO PERSONS_GROUPS (GROUP_ID, PERSON_ID) VALUES (1, 1)",
      "INSERT INTO PERSONS_GROUPS (GROUP_ID, PERSON_ID) VALUES (1, 2)",
      "INSERT INTO PERSONS_GROUPS (GROUP_ID, PERSON_ID) VALUES (1, 3)",
      "INSERT INTO PERSONS_GROUPS (GROUP_ID, PERSON_ID) VALUES (2, 1)",
      "INSERT INTO PERSONS_GROUPS (GROUP_ID, PERSON_ID) VALUES (2, 2)",
      "INSERT INTO PERSONS_GROUPS (GROUP_ID, PERSON_ID) VALUES (2, 4)",
      "INSERT INTO PERSONS_GROUPS (GROUP_ID, PERSON_ID) VALUES (2, 5)",

      "ALTER TABLE CONTACTS ADD CONSTRAINT CONTACT_PERSON_1 FOREIGN KEY (PERSON_ID) REFERENCES PERSONS (PERSON_ID)",
      "ALTER TABLE PERSONS ADD CONSTRAINT PERSON_ADDRESS_1 FOREIGN KEY (ADDRESS_ID) REFERENCES ADDRESSES (ADDRESS_ID)",
      "ALTER TABLE PERSONS ADD CONSTRAINT PERSON_CONTACT_1 FOREIGN KEY (MAIN_CONTACT_ID) REFERENCES CONTACTS (CONTACT_ID)",
      "ALTER TABLE PERSONS_GROUPS ADD CONSTRAINT PERSON_GROUP_1 FOREIGN KEY (PERSON_ID) REFERENCES PERSONS (PERSON_ID)",
      "ALTER TABLE PERSONS_GROUPS ADD CONSTRAINT PERSON_GROUP_2 FOREIGN KEY (GROUP_ID) REFERENCES GROUPS (GROUP_ID)", };

  public static void main(String[] args) {
    Connection connection = null;
    try {
      String driver = "org.apache.derby.jdbc.EmbeddedDriver";
      try {
        System.out.print("Loading the appropriate driver...");
        Class.forName(driver).newInstance();
        System.out.println("Done");
      } catch (ClassNotFoundException e) {
        System.err.println("Unable to load the JDBC driver " + driver);
        System.err.println("Please check your CLASSPATH.");
        e.printStackTrace();
        System.exit(-1);
      } catch (InstantiationException e) {
        System.err.println("Unable to instantiate the JDBC driver "
            + driver);
        e.printStackTrace();
        System.exit(-1);
      } catch (IllegalAccessException e) {
        System.err.println("Not allowed to access the JDBC driver "
            + driver);
        e.printStackTrace();
        System.exit(-1);
      }

      Properties props = new Properties();
      props.put("user", "x2x");
      props.put("password", "x2x");

      String dbName = "x2x_db";

      System.out.print("Connecting with the x2x database...");
      connection = DriverManager.getConnection("jdbc:derby:" + dbName
          + ";create=true", props);
      connection.setAutoCommit(false);
      System.out.println("Done");

      System.out.println("Executing the drop, create and insert queries");
      for (String sql : buildDatabase) {
        try {
          System.out.print("Executing '" + sql + "' ");
          connection.createStatement().execute(sql);
          connection.commit();
          System.out.println("Done");
        } catch (Throwable t) {
          connection.rollback();
          System.out.println("Failed");
          t.printStackTrace();
        }
      }
      System.out.println("Done");

      System.out.println("Finished");
    } catch (Exception e) {
      System.out.println("Failed");
      e.printStackTrace();
    } finally {
      if(connection != null){
        try {
          connection.close();
        }catch(Throwable t){}
      }
    }
  }
}

Java Persistence API (JPA)

For someone who's new to this field, the persistence API may be somewhat daunting, but one should not judge a book by its cover. The persistence API facilitates programming by reducing it. Before its introduction, a programmer had to manage the connection, and interact with the database him/herself. Now, with the new persistence API, all this code is intelligently incorporated within the API. With the help of annotations, the persistence API knows how to handle the class at hand and synchronise it with the database side seamlessly for the developer using it. We said enough already. Let's start working.

Entity

The Address class is used to represent an address in Java while the ADDRESSES table is used to save the data within the database. How will the persistence API synchronise these two?

For a class to be used with the persistence API, it must include the @Entity annotation. This means that the class will be persisted with the database using the JPA. The @Entity annotation alone is not enough to do the job as it's illustrated in the following listing. Note that all our examples are saved under the same package called x2x.

package x2x;

import javax.persistence.*;

@Entity
@Table(name = "ADDRESSES")
public class Address {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY) 
  @Column(name = "ADDRESS_ID")
  private long id;

  @Column(name = "ADDRESS", nullable = false) 
  private String address;

  //...
}

The above listing includes a total of five annotations. The @Table annotation is used to provide information about the table this class or better entity is to be synchronised with. By default, the class name is taken as the table name, but this can be differently set as required. All entity classes must have a primary key, which is marked with the @Id annotation. The address id, in this case, is also automatically generated by the database. Another annotation called @GeneratedValue is used to indicate that the value of this field is automatically generated by the database. By default the persistence API will use the field's name as the column name. When these are different, the @Column annotation has to be used to set the appropriate column name.

Relationships

Classes are logically related to each other through the use of fields. For example "a person has one address while one address can be used by more than one person" is represented by a reference of the Address class in the Person class as shown in bold in the following listing.

//...
public class Person {

  private Address address;

  //...

The persistence API provides a set of annotations which marks the relation between entities. There are four types of relations:

  • One-to-One
  • One-to-Many
  • Many-to-One
  • Many-to-Many

Each of these is discussed in detail below.

One-to-One

A person object has many contacts, but it has only one main contact. The relation between the main contact and person is one-to-one. The following listing illustrates a fragment from the Person class capturing this relation. Note that in this example, the relation between these two is unidirectional. The Contact class is not aware of this relation.

//...
public class Person {
  
  @OneToOne(optional = false)
  @JoinColumn(name = "MAIN_CONTACT_ID", 
                        referencedColumnName = "CONTACT_ID")
  private Contact mainContact;
  
  //...

Before we can understand how the relation between the entities works, let's recall the database relation between these two tables: The foreign key MAIN_CONTACT_ID in the PERSONS table is pointing to the primary key CONTACT_ID in the CONTACTS table. The @OneToOne annotation is very straightforward. It sets the relation between the two entities as one-to-one. The optional attribute sets the relation as obligatory. The other annotation, @JoinColumn, is very simple too. The name annotation attribute points to the foreign key while the referencedColumnName points to the primary key in the reference table (CONTACTS).

One-to-Many

A person can have many contacts. Thus there are two relations between the same two entities. The first one was discussed before. The second relation between these two is one-to-many. One person can have many contacts. A different fragment from the Person class is illustrated below. What's different from the previous example is that this relation is bidirectional.

//...
public class Person {
  
  @OneToMany(cascade = CascadeType.ALL, mappedBy = "person")
  private List<Contact> contacts;
  
  //...

As many of you would have predicted, the annotation which represents the one-to-many relation is called @OneToMany. Since this relation is bidirectional, the attribute mappedBy must provide the field's name that owns the relation in the other class. Note that this value is case-sensitive. The cascade attribute is an optional attribute defaulted to none. It can be set to one of the javax.persistence.CascadeType enum values: ALL; MERGE; PERSIST; REFRESH; REMOVE. This attribute is used by the persistence API to control what actions to cascade to the target entity. In our example all actions are propagated to the contacts instances related to this one.

Many-to-One

When the above is viewed from the other end we have: many contacts belong to one person. The relation between contacts and person is many-to-one.

//...
public class Contact {
  
  @ManyToOne(cascade = CascadeType.ALL)
  @JoinColumn(nullable = false, name = "PERSON_ID")
  private Person person;
  
  //...

The annotation @ManyToOne set the relation between the two classes through the following field: person. The field's name must match the value given to the mappedBy attribute in the @OneToMany in the Person class.

The annotation @JoinColumn can be seen as the representation of a foreign-key-column which connects the CONTACTS table with the PERSONS table.

Many-to-Many

A person may belong to many groups and a group can contain as many persons as required. The relation between the group and person is said to be many-to-many.

In all the relations discussed so far there was a table for class entity and the same tables used matched the classes involved. The common way for representing the many-to-many relation within a database is to use three tables: one for persons, one for groups and one to map the persons and groups together. In OOP, only two classes are required, the Person class and the Group class. Both classes can in turn contact a list of the other.

The persistence API provides several annotations to ease the linking process as shown in bold the following Group class listing.

//...
public class Group {
  
  @ManyToMany
  @JoinTable(name = "PERSONS_GROUPS")
  private List<Person> contacts;
  
//...
}

The annotation @ManyToMany is used to mark the many-to-many relation between this class (Group) and the field's content type class (Person), referred to as the inverse class. The field must be of type Set, List, Map or Collection (or any subclasses) as only these types are supported. The program will compile if other types are used but will produce a runtime exception.

The persistence API requires more information to link these two tables together. The @JoinTable annotation is used to provide information about the third table, the one that maps the person and group records. The @JoinTable annotation has six parameters, of which only one was used above. Two other parameters which are commonly used are the inverseJoinColumns and the joinColumns. The joinColumns represents the fields used in this entity (Group) to map to the other entity (Person), while the inverseJoinColumns represents the fields used by the other entity (Person) to map with this one (Group).

Together with the @JoinTable, the @JoinColumn annotation can be used to label the respective columns. These were not included in the above listing as the persistence API default values happen to match the database column names. The above listing can be changed as shown in bold in the following listing to also point to the respective column.

@ManyToMany
@JoinTable(name = "PERSONS_GROUPS", 
           joinColumns = { @JoinColumn(name = "GROUP_ID") }, 
           inverseJoinColumns = { @JoinColumn(name = "PERSON_ID") }  
           )
private List<Person> contacts;

The Persistence.xml file

The persistence API requires one xml file called persistence.xml, saved within the META-INF folder. This xml files includes the list of classes which will be managed by the persistence API together with database connection url, username and password and other parameters. The embedded version of the JavaDB is used in this article, thus the transaction type has to be set to resource local and the embedded version of the driver is used instead.

The database name and the persistence unit name do not necessary have to have the same name, but it's a good practice to use at least similar ones. Since the database is already set up, the toplink.ddl-generation is set to none. The persistence.xml is illustrated below.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="x2x_db" transaction-type="RESOURCE_LOCAL">

    <provider>
oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider
    </provider>

    <class>x2x.Address</class>
    <class>x2x.Contact</class>
    <class>x2x.Group</class>
    <class>x2x.Person</class>

    <properties>
      <property name="toplink.jdbc.user" 
                   value="x2x" />
      <property name="toplink.jdbc.password" 
                   value="x2x" />
      <property name="toplink.jdbc.url"
                   value="jdbc:derby:x2x_db" />
      <property name="toplink.jdbc.driver"
                   value="org.apache.derby.jdbc.EmbeddedDriver" />
      <property name="toplink.ddl-generation" 
                   value="none" />
    </properties>

  </persistence-unit>
</persistence>

Entity Manager

Now that we have everything set up, we can start querying the database using the javax.persistence.EntityManager. The first thing we need to create an instance of the entity manager using a factory such as javax.persistence.EntityManagerFactory as shown in the following listing.

EntityManagerFactory factory = 
    Persistence.createEntityManagerFactory("x2x_db");
EntityManager manager = factory.createEntityManager();

The persistence unit name must be provided to the factory to load the proper information from the persistence.xml file. With our entity manager created we can do anything with it without having to worry about complex data access objects. Selecting all persons and put them in a list can be achieved in two lines of code as shown below.

Query selectAllQuery = 
      manager.createQuery("SELECT p FROM Person p");
List allPersons = selectAllQuery.getResultList();
for (Person p : allPersons) {
  //...
}

It's good to understand that even though the parameter passed to the create query method above is very similar to SQL, it's not. Note that the persons table is called PERSONS and not Person. So how did it work? The provided name is the name of the entity we're querying.

This query not only loaded the persons' data from the PERSONS table but also loaded the address, groups and contacts information from the same database. All this was done without additional code. We can do more than simply loading data. A new address, for example, can be created and inserted without having to wonder about the SQL code behind it as illustrated below.

Address newAddress = new Address();
newAddress.setAddress("The new Place, Persistence Ave, Java");
manager.getTransaction().begin();
manager.persist(newAddress);
manager.getTransaction().commit();
System.out.println("New Address id: " + newAddress.getId());

The same address can be updated and deleted in a similar fashion.

// Update
newAddress.setAddress("The other Place, Persistence Ave, Java");
manager.getTransaction().begin();
manager.persist(newAddress);
manager.getTransaction().commit();

// Delete
manager.getTransaction().begin();
manager.remove(newAddress);
manager.getTransaction().commit();

Conclusion

JPA like other new APIs introduced new features that improve the productivity and minimise the maintenance costs. The traditional data access object classes can be replaced by the use of annotation. This article merely covers the relational aspect of this vast API. Further reading about the class Query, and annotations @NamedQuery and @NamedQueries would prove very useful especially when it comes to retrieving information from the database.

Monday 3 August 2009

JSP compile error in Eclipse

One of the most common problem when using Eclipse to develop web pages (JSPs) is the default JRE settings. By default Eclipse sets the default system JRE as its JRE. This sounds all good, but JSPs require a JDK instead of a JRE - this sounds weird. This article shows you how to solve this very small issue by changing the Eclipse Installed JREs settings.

To avoid confusion in this article, I'm going to use italics to refer to the JRE Eclipse name (nothing to do with Java unless otherwise told), that is, the name Eclipse uses and has nothing to do with the Java JRE. Also, JDK means Java Development Kit and JRE (not in italics) means Java Runtime Environment.

Set Eclipse Installed JREs

Check your JDK

Before you proceed, make sure that you have a JDK installed. You can do so by executing the following command on your command prompt.


C:\>javac -version
javac 1.6.0_02

In my case I have a copy of Java 1.6 update 2 installed. Your version may be different from the one displayed above, depending on the version you have installed. As long as the above command returns something (similar to the above) it's OK. If the above returns an error similar to following, it means that either you don't have a JDK installed or the JDK bin directory is not in your system path.


C:\>javac -version
'javac' is not recognized as an internal or external command, operable program or batch file.

In this case, browse to the folder where you think Java is installed (on Windows this is usually: C:\Program Files\Java or C:\Program Files (86)\Java in case of 64 bit Windows version) and check it yourself. Alternatively, visit Sun's website (http://java.sun.com) and download and install the JDK from there. Make sure to download the JDK and not the JRE.

Set the Installed JREs

Open Eclipse if it is not already running. Open the Preferences from the Windows menu as shown below.

Expand the Java node and select the Installed JREs sub-node.

JSPs require that Eclipse default Installed JRE is actually pointing to a JDK and not a JRE. Thus if your default Installed JRE is pointing to a JRE instead, you need to replace it with your JDK. This may sound weird since the dialog is asking you for a JRE.

The process is very simple:

  1. First add a new JRE by clicking the Add button. You cannot just remove your only JRE without first adding another JRE.
  2. Select Standard VM option from the list and click Next.
  3. Click the Directory button or manually enter the path to your (latest or which one you require) JDK directory on your local machine. Note that the JDK directory is the folder where JDK was installed. See the next screen shot.
  4. Wait for Eclipse to verify your entry and list the libraries.
  5. Optionally, you can change the JRE name to a name of your liking.
  6. Click Finish to complete the process.
  7. Set the new JRE (that is, the JDK just added) as your default JRE by checking the checkbox near the JRE friendly name (usually the first column).
  8. Optionally, you can remove the other JRE by first selecting it (not setting it as your default) and pressing the Remove button.
  9. Click OK to close the preferences dialog.

With the default JRE set to a JDK, test your JSPs and confirm that the errors are now gone and the JSPs are now compiling.