This is an automated email from the ASF dual-hosted git repository. radcortez pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/tomee.git
commit a8ea8ea274b051b8f5dec5584c7c2b837d7f54f3 Author: Mariani Federico <[email protected]> AuthorDate: Sat Dec 29 19:49:15 2018 +0100 TOMEE-2429 --- examples/mp-jsonb-custom-serializer/README.md | 459 +++++++++++++++++++++ examples/mp-jsonb-custom-serializer/pom.xml | 62 +++ .../main/java/org/superbiz/AddressSerializer.java | 20 + .../main/java/org/superbiz/JAXRSApplication.java | 9 + .../main/java/org/superbiz/JSONBConfiguration.java | 25 ++ .../main/java/org/superbiz/UserDeserializer.java | 26 ++ .../src/main/java/org/superbiz/model/Address.java | 36 ++ .../src/main/java/org/superbiz/model/User.java | 88 ++++ .../main/java/org/superbiz/rest/UserService.java | 39 ++ .../src/main/webapp/WEB-INF/web.xml | 23 ++ .../java/org/superbiz/rest/UserServiceTest.java | 47 +++ examples/pom.xml | 1 + 12 files changed, 835 insertions(+) diff --git a/examples/mp-jsonb-custom-serializer/README.md b/examples/mp-jsonb-custom-serializer/README.md new file mode 100644 index 0000000..4ed7e18 --- /dev/null +++ b/examples/mp-jsonb-custom-serializer/README.md @@ -0,0 +1,459 @@ +index-group=Unrevised +type=page +status=published +~~~~~~ + +This examples shows how to customize objects serialization/deserialization with jsonb for a JAX-RS Application. + +## Run and test Endpoint + +the application can be run with 'mvn clean install tomee:run' if port 8080 is available you can invoke the following endpoint: (GET) http://localhost:8080/mp-jsonb-custom-serializer/api/users that should respond with the following json: + + [ + { + "address":{ + "addr":"modified - addr1" + }, + "id":1, + "name":"user 1", + "registration":"2018-12-29T18:13:40.028" + }, + { + "address":{ + "addr":"modified - addr2" + }, + "id":2, + "name":"user 2", + "registration":"2018-12-29T18:13:40.028" + } + ] + +and the endpoint: (POST) http://localhost:8080/mp-jsonb-custom-serializer/api/users with a body like: + + { + "id": 1, + "name": "name1", + "extra": "extra1" + } + +which respond with the following json: + + { + "id": 1, + "name": "name1extra1", + "registration": "Sat Dec 29 19:48:05 CET 2018", + "address": null + } + +## @ApplicationPath + +JAXRS entry point class, as follows jaxrs will load all the annotated @Path classes and methods without specifying them. + + import javax.ws.rs.ApplicationPath; + import javax.ws.rs.core.Application; + + @ApplicationPath("api") + public class JAXRSApplication extends Application { + + } + +## @Path Rest resource + +Simple jaxrs class with a GET and a POST endpoint + + import java.util.ArrayList; + import java.util.List; + + import javax.ejb.Stateless; + import javax.ws.rs.Consumes; + import javax.ws.rs.GET; + import javax.ws.rs.POST; + import javax.ws.rs.Path; + import javax.ws.rs.Produces; + import javax.ws.rs.core.MediaType; + + import org.superbiz.model.Address; + import org.superbiz.model.User; + + @Path("users") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + @Stateless + public class UserService { + + @GET + public List<User> users() { + List<User> users = new ArrayList<>(); + User user1 = new User(1, "user 1", new Address("addr1")); + User user2 = new User(2, "user 2", new Address("addr2")); + users.add(user1); + users.add(user2); + + return users; + } + + @POST + public User addUser(User u) { + // Just to show the deserialization + return u; + } + } + + +## JSONB Configuration + +Implementing ContextResolver<> you can customize jaxrs defaults, in this example we are going to customize JSONB serialization for all objects of type Address, defined in AddressSerializer class + + import javax.json.bind.Jsonb; + import javax.json.bind.JsonbBuilder; + import javax.json.bind.JsonbConfig; + import javax.ws.rs.ext.ContextResolver; + import javax.ws.rs.ext.Provider; + + @Provider + public class JSONBConfiguration implements ContextResolver<Jsonb> { + + private Jsonb jsonb; + + public JSONBConfiguration() { + JsonbConfig config = new JsonbConfig().withFormatting(true).withSerializers(new AddressSerializer()); + + jsonb = JsonbBuilder.create(config); + } + + @Override + public Jsonb getContext(Class<?> type) { + return jsonb; + } + + } + +## Address serializer + +Simple Object serializer class that add 'modified' during serialization + + import javax.json.bind.serializer.JsonbSerializer; + import javax.json.bind.serializer.SerializationContext; + import javax.json.stream.JsonGenerator; + + import org.superbiz.model.Address; + + public class AddressSerializer implements JsonbSerializer<Address> { + + @Override + public void serialize(Address obj, JsonGenerator generator, SerializationContext ctx) { + if (obj != null) { + obj.setAddr("modified - " + obj.getAddr()); + ctx.serialize(obj, generator); + } + + } + + } + + +## User Deserializer + +Create an object from a json + + import java.lang.reflect.Type; + + import javax.json.JsonObject; + import javax.json.bind.serializer.DeserializationContext; + import javax.json.bind.serializer.JsonbDeserializer; + import javax.json.stream.JsonParser; + + import org.superbiz.model.User; + + public class UserDeserializer implements JsonbDeserializer<User> { + + @Override + public User deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) { + JsonObject jo = parser.getObject(); + String name = jo.get("name").toString().replace("\"", ""); + if (jo.get("extra") != null) { + name = name + jo.get("extra").toString().replace("\"", ""); + } + User u = new User(Integer.parseInt(jo.get("id").toString()), name, null); + + return u; + } + + } + +## Using the deserializer @JsonbTypeDeserializer @JsonbTypeSerializer + +With the annotation @JsonbTypeDeserializer or @JsonbTypeSerializer you can notify jsonb to use the custom deserializer + + import java.util.Date; + + import javax.json.bind.annotation.JsonbTypeDeserializer; + + import org.superbiz.UserDeserializer; + + @JsonbTypeDeserializer(UserDeserializer.class) + public class User { + + private Integer id; + private String name; + private Date registration = new Date(); + private Address address; + + public User(Integer id, String name, Address address) { + super(); + this.id = id; + this.name = name; + this.address = address; + } + + public User() { + super(); + } + + // ... GET/SET + + } + +## Accessing the rest endpoint + +The test spin up an openejb webapp and invoke the users endpoint + + import java.io.IOException; + + import javax.ws.rs.core.MediaType; + + import org.apache.cxf.jaxrs.client.WebClient; + import org.apache.openejb.jee.WebApp; + import org.apache.openejb.junit.ApplicationComposer; + import org.apache.openejb.testing.Classes; + import org.apache.openejb.testing.EnableServices; + import org.apache.openejb.testing.Module; + import org.junit.Assert; + import org.junit.Test; + import org.junit.runner.RunWith; + import org.superbiz.JAXRSApplication; + import org.superbiz.JSONBConfiguration; + import org.superbiz.model.User; + + @EnableServices(value = "jaxrs") + @RunWith(ApplicationComposer.class) + public class UserServiceTest { + + @Module + @Classes({ UserService.class, JAXRSApplication.class, JSONBConfiguration.class }) + public WebApp app() { + return new WebApp().contextRoot("test"); + } + + @Test + public void get() throws IOException { + final String message = WebClient.create("http://localhost:4204").path("/test/api/users").get(String.class); + + Assert.assertTrue(message.contains("modified - addr1")); + } + + @Test + public void post() throws IOException { + final String inputJson = "{ \"id\": 1, \"name\": \"user1\", \"extra\": \"extraField\"}"; + final User responseUser = WebClient.create("http://localhost:4204").path("/test/api/users") + .type(MediaType.APPLICATION_JSON).post(inputJson, User.class); + + Assert.assertTrue(!responseUser.getName().equals("user1")); + Assert.assertTrue(responseUser.getName().equals("user1" + "extraField")); + } + + } + + +# Running + +Running the example can be done from maven with a simple 'mvn clean install' command run from the 'mp-jsonb-custom-serializer' directory. + +When run you should see output similar to the following. + + ------------------------------------------------------- + T E S T S + ------------------------------------------------------- + Running org.superbiz.rest.UserServiceTest + INFO - Created new singletonService org.apache.openejb.cdi.ThreadSingletonServiceImpl@7823a2f9 + INFO - Succeeded in installing singleton service + INFO - Cannot find the configuration file [conf/openejb.xml]. Will attempt to create one for the beans deployed. + INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service) + INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager) + INFO - Creating TransactionManager(id=Default Transaction Manager) + INFO - Creating SecurityService(id=Default Security Service) + INFO - Initializing network services + INFO - Creating ServerService(id=cxf-rs) + INFO - Creating ServerService(id=httpejbd) + INFO - Created ServicePool 'httpejbd' with (10) core threads, limited to (200) threads with a queue of (9) + INFO - Initializing network services + INFO - ** Bound Services ** + INFO - NAME IP PORT + INFO - httpejbd 127.0.0.1 4204 + INFO - ------- + INFO - Ready! + INFO - Configuring enterprise application: /home/federico/Documents/PRIVATO/Apache/tomee/examples/mp-jsonb-custom-serializer/UserServiceTest + INFO - Auto-deploying ejb UserService: EjbDeployment(deployment-id=UserService) + INFO - Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container) + INFO - Auto-creating a container for bean org.superbiz.rest.UserServiceTest: Container(type=MANAGED, id=Default Managed Container) + INFO - Creating Container(id=Default Managed Container) + INFO - Using directory /tmp for stateful session passivation + INFO - Configuring Service(id=Default Stateless Container, type=Container, provider-id=Default Stateless Container) + INFO - Auto-creating a container for bean UserService: Container(type=STATELESS, id=Default Stateless Container) + INFO - Creating Container(id=Default Stateless Container) + INFO - Enterprise application "/home/federico/Documents/PRIVATO/Apache/tomee/examples/mp-jsonb-custom-serializer/UserServiceTest" loaded. + INFO - Creating dedicated application classloader for UserServiceTest + INFO - Assembling app: /home/federico/Documents/PRIVATO/Apache/tomee/examples/mp-jsonb-custom-serializer/UserServiceTest + INFO - Jndi(name=UserServiceLocalBean) --> Ejb(deployment-id=UserService) + INFO - Jndi(name=global/test/UserService!org.superbiz.rest.UserService) --> Ejb(deployment-id=UserService) + INFO - Jndi(name=global/test/UserService) --> Ejb(deployment-id=UserService) + INFO - Created Ejb(deployment-id=UserService, ejb-name=UserService, container=Default Stateless Container) + INFO - Started Ejb(deployment-id=UserService, ejb-name=UserService, container=Default Stateless Container) + INFO - Using readers: + INFO - org.apache.cxf.jaxrs.provider.PrimitiveTextProvider@6a1d204a + INFO - org.apache.cxf.jaxrs.provider.FormEncodingProvider@28a0fd6c + INFO - org.apache.cxf.jaxrs.provider.MultipartProvider@2b62442c + INFO - org.apache.cxf.jaxrs.provider.SourceProvider@66629f63 + INFO - org.apache.cxf.jaxrs.provider.JAXBElementTypedProvider@841e575 + INFO - org.apache.cxf.jaxrs.provider.JAXBElementProvider@27a5328c + INFO - org.apache.openejb.server.cxf.rs.johnzon.TomEEJsonbProvider@5ab14cb9 + INFO - org.apache.openejb.server.cxf.rs.johnzon.TomEEJsonpProvider@62dae245 + INFO - org.apache.cxf.jaxrs.provider.StringTextProvider@4b6579e8 + INFO - org.apache.cxf.jaxrs.provider.BinaryDataProvider@6fff253c + INFO - org.apache.cxf.jaxrs.provider.DataSourceProvider@6c6357f9 + INFO - Using writers: + INFO - org.apache.johnzon.jaxrs.WadlDocumentMessageBodyWriter@591e58fa + INFO - org.apache.cxf.jaxrs.nio.NioMessageBodyWriter@3954d008 + INFO - org.apache.cxf.jaxrs.provider.StringTextProvider@4b6579e8 + INFO - org.apache.cxf.jaxrs.provider.JAXBElementTypedProvider@841e575 + INFO - org.apache.cxf.jaxrs.provider.PrimitiveTextProvider@6a1d204a + INFO - org.apache.cxf.jaxrs.provider.FormEncodingProvider@28a0fd6c + INFO - org.apache.cxf.jaxrs.provider.MultipartProvider@2b62442c + INFO - org.apache.cxf.jaxrs.provider.SourceProvider@66629f63 + INFO - org.apache.cxf.jaxrs.provider.JAXBElementProvider@27a5328c + INFO - org.apache.openejb.server.cxf.rs.johnzon.TomEEJsonbProvider@5ab14cb9 + INFO - org.apache.openejb.server.cxf.rs.johnzon.TomEEJsonpProvider@62dae245 + INFO - org.apache.cxf.jaxrs.provider.BinaryDataProvider@6fff253c + INFO - org.apache.cxf.jaxrs.provider.DataSourceProvider@6c6357f9 + INFO - Using exception mappers: + INFO - org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper@403132fc + INFO - org.apache.openejb.server.cxf.rs.EJBExceptionMapper@32cb636e + INFO - org.apache.cxf.jaxrs.validation.ValidationExceptionMapper@71c5b236 + INFO - org.apache.openejb.server.cxf.rs.CxfRsHttpListener$CxfResponseValidationExceptionMapper@2cab9998 + INFO - REST Application: http://127.0.0.1:4204/test/api -> org.superbiz.JAXRSApplication@285d851a + INFO - Service URI: http://127.0.0.1:4204/test/api/users -> EJB org.superbiz.rest.UserService + INFO - GET http://127.0.0.1:4204/test/api/users -> List<User> users() + INFO - POST http://127.0.0.1:4204/test/api/users -> User addUser(User) + INFO - Deployed Application(path=/home/federico/Documents/PRIVATO/Apache/tomee/examples/mp-jsonb-custom-serializer/UserServiceTest) + INFO - Undeploying app: /home/federico/Documents/PRIVATO/Apache/tomee/examples/mp-jsonb-custom-serializer/UserServiceTest + INFO - Stopping network services + INFO - Stopping server services + INFO - Created new singletonService org.apache.openejb.cdi.ThreadSingletonServiceImpl@7823a2f9 + INFO - Succeeded in installing singleton service + INFO - Cannot find the configuration file [conf/openejb.xml]. Will attempt to create one for the beans deployed. + INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service) + INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager) + INFO - Creating TransactionManager(id=Default Transaction Manager) + INFO - Creating SecurityService(id=Default Security Service) + INFO - Initializing network services + INFO - Creating ServerService(id=cxf-rs) + INFO - Creating ServerService(id=httpejbd) + INFO - Created ServicePool 'httpejbd' with (10) core threads, limited to (200) threads with a queue of (9) + INFO - Initializing network services + INFO - ** Bound Services ** + INFO - NAME IP PORT + INFO - httpejbd 127.0.0.1 4204 + INFO - ------- + INFO - Ready! + INFO - Configuring enterprise application: /home/federico/Documents/PRIVATO/Apache/tomee/examples/mp-jsonb-custom-serializer/UserServiceTest + INFO - Auto-deploying ejb UserService: EjbDeployment(deployment-id=UserService) + INFO - Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container) + INFO - Auto-creating a container for bean org.superbiz.rest.UserServiceTest: Container(type=MANAGED, id=Default Managed Container) + INFO - Creating Container(id=Default Managed Container) + INFO - Using directory /tmp for stateful session passivation + INFO - Configuring Service(id=Default Stateless Container, type=Container, provider-id=Default Stateless Container) + INFO - Auto-creating a container for bean UserService: Container(type=STATELESS, id=Default Stateless Container) + INFO - Creating Container(id=Default Stateless Container) + INFO - Enterprise application "/home/federico/Documents/PRIVATO/Apache/tomee/examples/mp-jsonb-custom-serializer/UserServiceTest" loaded. + INFO - Creating dedicated application classloader for UserServiceTest + INFO - Assembling app: /home/federico/Documents/PRIVATO/Apache/tomee/examples/mp-jsonb-custom-serializer/UserServiceTest + INFO - Jndi(name=UserServiceLocalBean) --> Ejb(deployment-id=UserService) + INFO - Jndi(name=global/test/UserService!org.superbiz.rest.UserService) --> Ejb(deployment-id=UserService) + INFO - Jndi(name=global/test/UserService) --> Ejb(deployment-id=UserService) + INFO - Created Ejb(deployment-id=UserService, ejb-name=UserService, container=Default Stateless Container) + INFO - Started Ejb(deployment-id=UserService, ejb-name=UserService, container=Default Stateless Container) + INFO - Using readers: + INFO - org.apache.cxf.jaxrs.provider.PrimitiveTextProvider@51a06cbe + INFO - org.apache.cxf.jaxrs.provider.FormEncodingProvider@6cc0bcf6 + INFO - org.apache.cxf.jaxrs.provider.MultipartProvider@29539e36 + INFO - org.apache.cxf.jaxrs.provider.SourceProvider@32f61a31 + INFO - org.apache.cxf.jaxrs.provider.JAXBElementTypedProvider@f5c79a6 + INFO - org.apache.cxf.jaxrs.provider.JAXBElementProvider@669253b7 + INFO - org.apache.openejb.server.cxf.rs.johnzon.TomEEJsonbProvider@5ab14cb9 + INFO - org.apache.openejb.server.cxf.rs.johnzon.TomEEJsonpProvider@62dae245 + INFO - org.apache.cxf.jaxrs.provider.StringTextProvider@3dddbe65 + INFO - org.apache.cxf.jaxrs.provider.BinaryDataProvider@49a64d82 + INFO - org.apache.cxf.jaxrs.provider.DataSourceProvider@344561e0 + INFO - Using writers: + INFO - org.apache.johnzon.jaxrs.WadlDocumentMessageBodyWriter@66d23e4a + INFO - org.apache.cxf.jaxrs.nio.NioMessageBodyWriter@36ac8a63 + INFO - org.apache.cxf.jaxrs.provider.StringTextProvider@3dddbe65 + INFO - org.apache.cxf.jaxrs.provider.JAXBElementTypedProvider@f5c79a6 + INFO - org.apache.cxf.jaxrs.provider.PrimitiveTextProvider@51a06cbe + INFO - org.apache.cxf.jaxrs.provider.FormEncodingProvider@6cc0bcf6 + INFO - org.apache.cxf.jaxrs.provider.MultipartProvider@29539e36 + INFO - org.apache.cxf.jaxrs.provider.SourceProvider@32f61a31 + INFO - org.apache.cxf.jaxrs.provider.JAXBElementProvider@669253b7 + INFO - org.apache.openejb.server.cxf.rs.johnzon.TomEEJsonbProvider@5ab14cb9 + INFO - org.apache.openejb.server.cxf.rs.johnzon.TomEEJsonpProvider@62dae245 + INFO - org.apache.cxf.jaxrs.provider.BinaryDataProvider@49a64d82 + INFO - org.apache.cxf.jaxrs.provider.DataSourceProvider@344561e0 + INFO - Using exception mappers: + INFO - org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper@4d9d1b69 + INFO - org.apache.openejb.server.cxf.rs.EJBExceptionMapper@5305c37d + INFO - org.apache.cxf.jaxrs.validation.ValidationExceptionMapper@52c8295b + INFO - org.apache.openejb.server.cxf.rs.CxfRsHttpListener$CxfResponseValidationExceptionMapper@251f7d26 + INFO - REST Application: http://127.0.0.1:4204/test/api -> org.superbiz.JAXRSApplication@77b21474 + INFO - Service URI: http://127.0.0.1:4204/test/api/users -> EJB org.superbiz.rest.UserService + INFO - GET http://127.0.0.1:4204/test/api/users -> List<User> users() + INFO - POST http://127.0.0.1:4204/test/api/users -> User addUser(User) + INFO - Deployed Application(path=/home/federico/Documents/PRIVATO/Apache/tomee/examples/mp-jsonb-custom-serializer/UserServiceTest) + INFO - Undeploying app: /home/federico/Documents/PRIVATO/Apache/tomee/examples/mp-jsonb-custom-serializer/UserServiceTest + INFO - Stopping network services + INFO - Stopping server services + Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.31 sec + + Results : + + Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 + +## Inside the jar + +javaee-api:8.0 brings in all the dependencies needed to spin up a working REST application. + +If we look at the jar built by maven, we'll see the application itself is quite small: + + $ jar tvf target/mp-jsonb-custom-serializer-8.0.0-SNAPSHOT.war + 0 Sat Dec 29 19:10:44 CET 2018 META-INF/ + 134 Sat Dec 29 19:10:42 CET 2018 META-INF/MANIFEST.MF + 0 Sat Dec 29 19:10:42 CET 2018 WEB-INF/ + 0 Sat Dec 29 19:10:42 CET 2018 WEB-INF/classes/ + 0 Sat Dec 29 19:10:42 CET 2018 WEB-INF/classes/org/ + 0 Sat Dec 29 19:10:42 CET 2018 WEB-INF/classes/org/superbiz/ + 0 Sat Dec 29 19:10:42 CET 2018 WEB-INF/classes/org/superbiz/model/ + 0 Sat Dec 29 19:10:42 CET 2018 WEB-INF/classes/org/superbiz/rest/ + 790 Sat Dec 29 19:10:38 CET 2018 WEB-INF/classes/org/superbiz/model/Address.class + 2093 Sat Dec 29 19:10:38 CET 2018 WEB-INF/classes/org/superbiz/model/User.class + 2063 Sat Dec 29 19:10:38 CET 2018 WEB-INF/classes/org/superbiz/UserDeserializer.class + 402 Sat Dec 29 19:10:38 CET 2018 WEB-INF/classes/org/superbiz/JAXRSApplication.class + 1461 Sat Dec 29 19:10:38 CET 2018 WEB-INF/classes/org/superbiz/AddressSerializer.class + 1498 Sat Dec 29 19:10:38 CET 2018 WEB-INF/classes/org/superbiz/rest/UserService.class + 1549 Sat Dec 29 19:10:38 CET 2018 WEB-INF/classes/org/superbiz/JSONBConfiguration.class + 1241 Sat Dec 29 17:52:48 CET 2018 WEB-INF/web.xml + 0 Sat Dec 29 19:10:44 CET 2018 META-INF/maven/ + 0 Sat Dec 29 19:10:44 CET 2018 META-INF/maven/org.superbiz/ + 0 Sat Dec 29 19:10:44 CET 2018 META-INF/maven/org.superbiz/mp-jsonb-custom-serializer/ + 1811 Sat Dec 29 17:53:36 CET 2018 META-INF/maven/org.superbiz/mp-jsonb-custom-serializer/pom.xml + 132 Sat Dec 29 19:10:42 CET 2018 META-INF/maven/org.superbiz/mp-jsonb-custom-serializer/pom.properties + +This single jar could be deployed any any compliant Java EE implementation. In TomEE you'd simply place it in the `tomee.home/webapps/` directory. \ No newline at end of file diff --git a/examples/mp-jsonb-custom-serializer/pom.xml b/examples/mp-jsonb-custom-serializer/pom.xml new file mode 100644 index 0000000..8ec6910 --- /dev/null +++ b/examples/mp-jsonb-custom-serializer/pom.xml @@ -0,0 +1,62 @@ +<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>org.superbiz</groupId> + <artifactId>mp-jsonb-custom-serializer</artifactId> + <version>8.0.0-SNAPSHOT</version> + <packaging>war</packaging> + <name>OpenEJB :: Examples :: Microprofile JSONB Custom Serializer/Deserializer</name> + + <properties> + <version.javaee-api>8.0</version.javaee-api> + <tomee.version>${project.version}</tomee.version> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencies> + <dependency> + <groupId>org.apache.tomee</groupId> + <artifactId>javaee-api</artifactId> + <version>${version.javaee-api}</version> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.tomee</groupId> + <artifactId>openejb-cxf-rs</artifactId> + <version>8.0.0-SNAPSHOT</version> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.tomee.maven</groupId> + <artifactId>tomee-maven-plugin</artifactId> + <version>${project.version}</version> + <configuration> + <tomeeClassifier>microprofile</tomeeClassifier> + <context>${project.artifactId}</context> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.7.0</version> + <configuration> + <source>1.8</source> + <target>1.8</target> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/examples/mp-jsonb-custom-serializer/src/main/java/org/superbiz/AddressSerializer.java b/examples/mp-jsonb-custom-serializer/src/main/java/org/superbiz/AddressSerializer.java new file mode 100644 index 0000000..f8ef80c --- /dev/null +++ b/examples/mp-jsonb-custom-serializer/src/main/java/org/superbiz/AddressSerializer.java @@ -0,0 +1,20 @@ +package org.superbiz; + +import javax.json.bind.serializer.JsonbSerializer; +import javax.json.bind.serializer.SerializationContext; +import javax.json.stream.JsonGenerator; + +import org.superbiz.model.Address; + +public class AddressSerializer implements JsonbSerializer<Address> { + + @Override + public void serialize(Address obj, JsonGenerator generator, SerializationContext ctx) { + if (obj != null) { + obj.setAddr("modified - " + obj.getAddr()); + ctx.serialize(obj, generator); + } + + } + +} diff --git a/examples/mp-jsonb-custom-serializer/src/main/java/org/superbiz/JAXRSApplication.java b/examples/mp-jsonb-custom-serializer/src/main/java/org/superbiz/JAXRSApplication.java new file mode 100644 index 0000000..e3fdcfc --- /dev/null +++ b/examples/mp-jsonb-custom-serializer/src/main/java/org/superbiz/JAXRSApplication.java @@ -0,0 +1,9 @@ +package org.superbiz; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +@ApplicationPath("api") +public class JAXRSApplication extends Application { + +} diff --git a/examples/mp-jsonb-custom-serializer/src/main/java/org/superbiz/JSONBConfiguration.java b/examples/mp-jsonb-custom-serializer/src/main/java/org/superbiz/JSONBConfiguration.java new file mode 100644 index 0000000..5e2a9fb --- /dev/null +++ b/examples/mp-jsonb-custom-serializer/src/main/java/org/superbiz/JSONBConfiguration.java @@ -0,0 +1,25 @@ +package org.superbiz; + +import javax.json.bind.Jsonb; +import javax.json.bind.JsonbBuilder; +import javax.json.bind.JsonbConfig; +import javax.ws.rs.ext.ContextResolver; +import javax.ws.rs.ext.Provider; + +@Provider +public class JSONBConfiguration implements ContextResolver<Jsonb> { + + private Jsonb jsonb; + + public JSONBConfiguration() { + JsonbConfig config = new JsonbConfig().withFormatting(true).withSerializers(new AddressSerializer()); + + jsonb = JsonbBuilder.create(config); + } + + @Override + public Jsonb getContext(Class<?> type) { + return jsonb; + } + +} diff --git a/examples/mp-jsonb-custom-serializer/src/main/java/org/superbiz/UserDeserializer.java b/examples/mp-jsonb-custom-serializer/src/main/java/org/superbiz/UserDeserializer.java new file mode 100644 index 0000000..e641f90 --- /dev/null +++ b/examples/mp-jsonb-custom-serializer/src/main/java/org/superbiz/UserDeserializer.java @@ -0,0 +1,26 @@ +package org.superbiz; + +import java.lang.reflect.Type; + +import javax.json.JsonObject; +import javax.json.bind.serializer.DeserializationContext; +import javax.json.bind.serializer.JsonbDeserializer; +import javax.json.stream.JsonParser; + +import org.superbiz.model.User; + +public class UserDeserializer implements JsonbDeserializer<User> { + + @Override + public User deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) { + JsonObject jo = parser.getObject(); + String name = jo.get("name").toString().replace("\"", ""); + if (jo.get("extra") != null) { + name = name + jo.get("extra").toString().replace("\"", ""); + } + User u = new User(Integer.parseInt(jo.get("id").toString()), name, null); + + return u; + } + +} diff --git a/examples/mp-jsonb-custom-serializer/src/main/java/org/superbiz/model/Address.java b/examples/mp-jsonb-custom-serializer/src/main/java/org/superbiz/model/Address.java new file mode 100644 index 0000000..e6fe961 --- /dev/null +++ b/examples/mp-jsonb-custom-serializer/src/main/java/org/superbiz/model/Address.java @@ -0,0 +1,36 @@ +package org.superbiz.model; + +public class Address { + + private String addr; + + /** + * @return the addr + */ + public String getAddr() { + return addr; + } + + /** + * @param addr the addr to set + */ + public void setAddr(String addr) { + this.addr = addr; + } + + public Address(String addr) { + super(); + this.addr = addr; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "Address [addr=" + addr + "]"; + } + +} diff --git a/examples/mp-jsonb-custom-serializer/src/main/java/org/superbiz/model/User.java b/examples/mp-jsonb-custom-serializer/src/main/java/org/superbiz/model/User.java new file mode 100644 index 0000000..f432149 --- /dev/null +++ b/examples/mp-jsonb-custom-serializer/src/main/java/org/superbiz/model/User.java @@ -0,0 +1,88 @@ +package org.superbiz.model; + +import java.util.Date; + +import javax.json.bind.annotation.JsonbTypeDeserializer; + +import org.superbiz.UserDeserializer; + +@JsonbTypeDeserializer(UserDeserializer.class) +public class User { + + private Integer id; + private String name; + private Date registration = new Date(); + private Address address; + + public User(Integer id, String name, Address address) { + super(); + this.id = id; + this.name = name; + this.address = address; + } + + public User() { + super(); + } + + /** + * @return the address + */ + public Address getAddress() { + return address; + } + + /** + * @param address the address to set + */ + public void setAddress(Address address) { + this.address = address; + } + + /** + * @return the id + */ + public Integer getId() { + return id; + } + + /** + * @param id the id to set + */ + public void setId(Integer id) { + this.id = id; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + public Date getRegistration() { + return registration; + } + + public void setRegistration(Date registration) { + this.registration = registration; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "User [id=" + id + ", name=" + name + ", registration=" + registration + ", address=" + address + "]"; + } + +} diff --git a/examples/mp-jsonb-custom-serializer/src/main/java/org/superbiz/rest/UserService.java b/examples/mp-jsonb-custom-serializer/src/main/java/org/superbiz/rest/UserService.java new file mode 100644 index 0000000..817d5a2 --- /dev/null +++ b/examples/mp-jsonb-custom-serializer/src/main/java/org/superbiz/rest/UserService.java @@ -0,0 +1,39 @@ +package org.superbiz.rest; + +import java.util.ArrayList; +import java.util.List; + +import javax.ejb.Stateless; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.superbiz.model.Address; +import org.superbiz.model.User; + +@Path("users") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +@Stateless +public class UserService { + + @GET + public List<User> users() { + List<User> users = new ArrayList<>(); + User user1 = new User(1, "user 1", new Address("addr1")); + User user2 = new User(2, "user 2", new Address("addr2")); + users.add(user1); + users.add(user2); + + return users; + } + + @POST + public User addUser(User u) { + // Just to show the deserialization + return u; + } +} diff --git a/examples/mp-jsonb-custom-serializer/src/main/webapp/WEB-INF/web.xml b/examples/mp-jsonb-custom-serializer/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..17b4115 --- /dev/null +++ b/examples/mp-jsonb-custom-serializer/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<web-app xmlns="http://java.sun.com/xml/ns/javaee" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" + metadata-complete="false" + version="2.5"> + + <display-name>Microprofile JSONB Custom Serializer/Deserializer</display-name> +</web-app> \ No newline at end of file diff --git a/examples/mp-jsonb-custom-serializer/src/test/java/org/superbiz/rest/UserServiceTest.java b/examples/mp-jsonb-custom-serializer/src/test/java/org/superbiz/rest/UserServiceTest.java new file mode 100644 index 0000000..ca9ddae --- /dev/null +++ b/examples/mp-jsonb-custom-serializer/src/test/java/org/superbiz/rest/UserServiceTest.java @@ -0,0 +1,47 @@ +package org.superbiz.rest; + +import java.io.IOException; + +import javax.ws.rs.core.MediaType; + +import org.apache.cxf.jaxrs.client.WebClient; +import org.apache.openejb.jee.WebApp; +import org.apache.openejb.junit.ApplicationComposer; +import org.apache.openejb.testing.Classes; +import org.apache.openejb.testing.EnableServices; +import org.apache.openejb.testing.Module; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.superbiz.JAXRSApplication; +import org.superbiz.JSONBConfiguration; +import org.superbiz.model.User; + +@EnableServices(value = "jaxrs") +@RunWith(ApplicationComposer.class) +public class UserServiceTest { + + @Module + @Classes({ UserService.class, JAXRSApplication.class, JSONBConfiguration.class }) + public WebApp app() { + return new WebApp().contextRoot("test"); + } + + @Test + public void get() throws IOException { + final String message = WebClient.create("http://localhost:4204").path("/test/api/users").get(String.class); + + Assert.assertTrue(message.contains("modified - addr1")); + } + + @Test + public void post() throws IOException { + final String inputJson = "{ \"id\": 1, \"name\": \"user1\", \"extra\": \"extraField\"}"; + final User responseUser = WebClient.create("http://localhost:4204").path("/test/api/users") + .type(MediaType.APPLICATION_JSON).post(inputJson, User.class); + + Assert.assertTrue(!responseUser.getName().equals("user1")); + Assert.assertTrue(responseUser.getName().equals("user1" + "extraField")); + } + +} diff --git a/examples/pom.xml b/examples/pom.xml index e9fbfd4..0fb53a5 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -183,6 +183,7 @@ <module>mvc-resteasy</module> <module>mp-custom-healthcheck</module> <module>mp-jsonb-configuration</module> + <module>mp-jsonb-custom-serializer</module> </modules> <dependencies>
