Enterprise Java
Bidirectional relationship with Jackson in REST web services in WildFly
This is an example for a Bidirectional relationship between Java entities in a REST web service with the Jackson API.
- Assume we have a bidirectional relationship between two entities Parent and Child.
- Using MySQL workbench to generate the SQL schema file for this two tables.0102030405060708091011121314151617181920212223242526272829303132
DROP
SCHEMA
IF EXISTS `bidirectional_schema` ;
CREATE
SCHEMA
IF
NOT
EXISTS `bidirectional_schema`
DEFAULT
CHARACTER
SET
utf8 ;
USE `bidirectional_schema` ;
-- -----------------------------------------------------
-- Table `bidirectional_schema`.`PARENT`
-- -----------------------------------------------------
DROP
TABLE
IF EXISTS `bidirectional_schema`.`PARENT` ;
CREATE
TABLE
IF
NOT
EXISTS `bidirectional_schema`.`PARENT` (
`PARENT_ID`
INT
NOT
NULL
,
`PARENT_CONTENT`
VARCHAR
(45)
NULL
,
PRIMARY
KEY
(`PARENT_ID`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `bidirectional_schema`.`CHILD`
-- -----------------------------------------------------
DROP
TABLE
IF EXISTS `bidirectional_schema`.`CHILD` ;
CREATE
TABLE
IF
NOT
EXISTS `bidirectional_schema`.`CHILD` (
`CHILD_ID`
INT
NOT
NULL
,
`CHILD_CONTENT`
VARCHAR
(45)
NULL
,
`PARENT_PARENT_ID`
INT
NOT
NULL
,
PRIMARY
KEY
(`CHILD_ID`) ,
INDEX
`fk_CHILD_PARENT_idx` (`PARENT_PARENT_ID`
ASC
) ,
CONSTRAINT
`fk_CHILD_PARENT`
FOREIGN
KEY
(`PARENT_PARENT_ID` )
REFERENCES
`bidirectional_schema`.`PARENT` (`PARENT_ID` )
ON
DELETE
NO
ACTION
ON
UPDATE
NO
ACTION
)
ENGINE = InnoDB;
- Then we will insert some data to those two tables through this insert statements:123
INSERT INTO `bidirectional_schema`.`parent` (`PARENT_ID`, `PARENT_CONTENT`) VALUES (
'1'
,
'First Parent'
);
INSERT INTO `bidirectional_schema`.`child` (`CHILD_ID`, `CHILD_CONTENT`, `PARENT_PARENT_ID`) VALUES (
'1'
,
'First Child'
,
'1'
);
INSERT INTO `bidirectional_schema`.`child` (`CHILD_ID`, `CHILD_CONTENT`, `PARENT_PARENT_ID`) VALUES (
'2'
,
'Second Child'
,
'1'
);
- The Maven dependencies for the Jackson API that are required for this example.010203040506070809101112131415
<
dependency
>
<
groupid
>com.fasterxml.jackson.core</
groupid
>
<
artifactid
>jackson-annotations</
artifactid
>
<
version
>2.5.2</
version
>
</
dependency
>
<
dependency
>
<
groupid
>com.fasterxml.jackson.core</
groupid
>
<
artifactid
>jackson-core</
artifactid
>
<
version
>2.5.2</
version
>
</
dependency
>
<
dependency
>
<
groupid
>com.fasterxml.jackson.core</
groupid
>
<
artifactid
>jackson-databind</
artifactid
>
<
version
>2.5.2</
version
>
</
dependency
>
Also, you can pick up your required Java EE dependencies from this link: https://wikis.oracle.com/display/GlassFish/Java+EE+7+Maven+Coordinates
- Using Eclipse to generate Entities from the above tables. File -> New -> Other, then from the wizard choose JPA Entities from Tables. A wizard will show up to create a connection to the schema that’s already created. Then select the two tables child and parent. Finally make sure that the “List generated classes in persistence.xml”.
You can proceed and follow the default settings but I chose the mapping settings as bellow:
- There is nothing fancy about the persistence.xml. But there are two points to consider. First, I didn’t specify the persistence provider as I tend to use WildFly so the application will use the default persistence provider which is Hibernate. Second, I created a datasource on WildFly so that it can be used to connect to our schema. Thirds, I used EclipseLink that’s why I’m using this JPA provider org.eclipse.persistence.jpa.PersistenceProvider. Check this post to point WildFly to EclipseLink.123456789
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<
persistence
version
=
"2.1"
xmlns
=
"http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
=
"http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
>
<
persistence-unit
name
=
"BidirectionalPU"
>
<
provider
>org.eclipse.persistence.jpa.PersistenceProvider</
provider
>
<
jta-data-source
>java:jboss/datasources/Bidirectional_DataSource</
jta-data-source
>
<
class
>com.ithinkisink.entity.Child</
class
>
<
class
>com.ithinkisink.entity.Parent</
class
>
</
persistence-unit
>
</
persistence
>
- The first class that we will implement is the ApplicationConfiguration class that will point to the parent path of our coming REST services.010203040506070809101112131415
package
com.ithinkisink;
import
javax.inject.Singleton;
import
javax.ws.rs.ApplicationPath;
import
javax.ws.rs.core.Application;
/**
*
* @author Belal
*
*/
@Singleton
@ApplicationPath
(
"rest"
)
public
class
ApplicationConfiguration
extends
Application {
}
- Then we will create MyService class that will have two REST web services. The first will retrieve a parent with a children fetched. The second one is an opposite to this and will retrieve a child with it’s parent fetched.0102030405060708091011121314151617181920212223242526272829303132333435363738
package
com.ithinkisink.service;
package
com.ithinkisink.service;
import
javax.ejb.EJB;
import
javax.ws.rs.GET;
import
javax.ws.rs.Path;
import
javax.ws.rs.Produces;
import
javax.ws.rs.core.MediaType;
import
com.ithinkisink.entity.Child;
import
com.ithinkisink.entity.Parent;
/**
*
* @author Belal
*
*/
@Path
(
"MyService"
)
public
class
MyService {
@EJB
MyServiceDAO myServiceDAO;
@GET
@Path
(
"/retrieveParentWithChildren"
)
@Produces
(MediaType.APPLICATION_JSON)
public
Parent retrieveParentWithChildren() {
return
myServiceDAO.retrieveParentWithChildren();
}
@GET
@Path
(
"/retrieveChildWithParent"
)
@Produces
(MediaType.APPLICATION_JSON)
public
Child retrieveChildWithParent() {
return
myServiceDAO.retrieveChildWithParent();
}
}
- Then we will create ServiceDAO and notice that the EntityManager is injected with a connection to the persistence unit that we already defined in the persistence.xml. I passed the name of the persistence unit to make this point clear. But you can just use the annotation @PersistenceContext without specifying the unitName attribute then it will use our persistence unit because there is no other persistence unit defined in our application.010203040506070809101112131415161718192021222324252627282930
package
com.ithinkisink.service;
import
javax.ejb.Stateless;
import
javax.persistence.EntityManager;
import
javax.persistence.PersistenceContext;
import
javax.persistence.Query;
import
com.ithinkisink.entity.Child;
import
com.ithinkisink.entity.Parent;
@Stateless
public
class
MyServiceDAO {
@PersistenceContext
(unitName=
"BidirectionalPU"
)
protected
EntityManager entityManager;
public
Parent retrieveParentWithChildren() {
int
parentId =
1
;
Query q = entityManager.createQuery(
"SELECT p FROM "
+
"Parent "
+
"p JOIN FETCH p.childs WHERE p.parentId = :parentId "
);
q.setParameter(
"parentId"
, parentId);
return
(q.getResultList().size() >
0
) ? (Parent) q.getResultList().get(
0
) :
null
;
}
public
Child retrieveChildWithParent() {
int
childId =
1
;
Query q = entityManager.createQuery(
"SELECT c FROM "
+
"Child "
+
"c JOIN FETCH c.parent WHERE c.childId = :childId "
);
q.setParameter(
"childId"
, childId);
return
(q.getResultList().size() >
0
) ? (Child) q.getResultList().get(
0
) :
null
;
}
}
- Now that our application is ready for testing will add it to the WildFly server. Then starting the server should be successful.
- For the sake of simplicity, I used Postman to test the running REST web services. So bellow are screenshots from the result on Postman.
- You can find the complete example on my Github from this link: https://github.com/belalgalal/Blogging/tree/master/BidirectionalRESTJson
Reference: | Bidirectional relationship with Jackson in REST web services in WildFly from our JCG partner Belal Galal at the I think, I sink! blog. |