package data; import java.io.Serializable; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; @XmlAccessorType(XmlAccessType.FIELD) public class Material implements Serializable { private static final long serialVersionUID = 1L; @XmlAttribute int id; private String title; private String location; public Material() {} public Material(int id, String name, String location2) { this.id = id; this.title = name; this.location = location2; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } public void update(String name, String location2) { this.title = name; this.location = location2; } } |
Each course has materials. I use JAXB annotations, because I want to serialize data as XML (as well as JSON, but I'm using the defaults for JSON):
package data; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementWrapper; @XmlAccessorType(XmlAccessType.FIELD) public class Course implements Serializable { private static final long serialVersionUID = 1L; @XmlAttribute private int id; private String name; @XmlElementWrapper(name="materials") @XmlElement(name="material") private List<Material> materials; public Course() { super(); } public Course(int id, String name2) { this.name = name2; this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void addMaterial(Material material) { if (this.materials == null) this.materials = new ArrayList<>(); this.materials.add(material); } public void deleteMaterial(Material material) { if (this.materials == null) return; //XXX: silent error? this.materials.remove(material); } public List<Material> getMaterials() { return this.materials; } } |
And now a list of courses:
package data; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name="ListCourses") public class ListCourses implements Serializable { private static final long serialVersionUID = 1L; private List<Course> courses; public ListCourses() { this.courses = new ArrayList<>(); } public List<Course> getCourses() { return courses; } public void setCourses(List<Course> courses) { this.courses = courses; } public void addCourse(Course c) { this.courses.add(c); } public Course get(int id) { return this.courses.get(id); } } |
I have an Enterprise JavaBean that initializes some data to give back to the REST service. In practice, this EJB would typically go to a database to get the data in need:
package ejb; import javax.ejb.LocalBean; import javax.ejb.Stateless; import data.Course; import data.ListCourses; import data.Material; /** * Session Bean implementation class MyBean */ @Stateless @LocalBean public class MyBean { private ListCourses lc; /** * Default constructor. */ public MyBean() { Course courses[] = {new Course(1, "IS"), new Course(2, "ES"), new Course(3, "PPP")}; Material materials[] = {new Material(1, "book", "/usr"), new Material(2, "slides", "/usr/slides"), new Material(3, "exercises", "/usr/exercises")}; courses[0].addMaterial(materials[0]); courses[0].addMaterial(materials[1]); courses[1].addMaterial(materials[0]); courses[1].addMaterial(materials[2]); courses[2].addMaterial(materials[1]); courses[2].addMaterial(materials[2]); lc = new ListCourses(); for (Course c : courses) lc.addCourse(c); } public ListCourses getListCourses() { return this.lc; } public Course getCourse(int id) { return this.lc.get(id); } } |
And now the two main classes of the example. First the "Root resource class". Please note the method name (@Get), the path (@Path), the MIME media type of the response (@Produces). I don't have any example with @Consumes, which specifies the MIME media type of the input:
package rest; import java.util.List; import javax.enterprise.context.RequestScoped; //import javax.naming.InitialContext; import javax.naming.NamingException; import javax.inject.Inject; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import data.Course; import data.ListCourses; import ejb.MyBean; @Path("/project3webservices") @RequestScoped public class WebServicesServer { @Inject MyBean db; public WebServicesServer() throws NamingException { System.out.println("WebServicesServer created. db = " + this.db); } // http://localhost:8080/play-REST-server/webapi/project3webservices/gettext @GET @Path("gettext") @Produces({MediaType.TEXT_PLAIN}) public String getText() { return "Hello World!"; } // http://localhost:8080/play-REST-server/webapi/project3webservices/getmaterials @GET @Path("getmaterials") @Produces({MediaType.APPLICATION_XML}) public ListCourses getAllMaterials() { return db.getListCourses(); } // http://localhost:8080/play-REST-server/webapi/project3webservices/getstudents?id=1 @GET @Path("getstudents") @Produces({MediaType.APPLICATION_JSON}) public Course getAllStudents(@QueryParam("courseid") int id) { return db.getCourse(id); } } |
And then a class to define the root application path:
package rest; import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; @ApplicationPath("webapi") public class HelloWorldApplication extends Application { } |
Finally, the pom.xml. You may specify the goals (mvn) clean install wildfly:deploy for WildFly. Assuming WildFly is running and configured with the default ports, this project will be immediately deployed.
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>is</groupId>
<artifactId>project3-REST-server</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>project3 REST web services</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.sun.xml.ws/jaxws-rt -->
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.3.2</version>
<type>pom</type>
</dependency>
<!-- https://mvnrepository.com/artifact/javax/javaee-api -->
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>play-REST-server</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>12</source>
<target>12</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.wildfly.plugins</groupId>
<artifactId>wildfly-maven-plugin</artifactId>
<version>2.0.1.Final</version>
<configuration>
<hostname>localhost</hostname>
<port>9990</port>
</configuration>
</plugin>
</plugins>
</build>
</project>
|
Then, you may go to a browser to invoke the three URLs I show in the root resource class to get the following results. One should notice the awesome fact that we are getting XML and JSON as requested using nothing more than a couple of annotations. Java EE makes that for us: