You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by jg...@apache.org on 2023/11/08 10:00:09 UTC
(tomee) 02/02: feat(#TOMEE-4268): MicroProfile OpenAPI Reader example.
This is an automated email from the ASF dual-hosted git repository.
jgallimore pushed a commit to branch tomee-9.x
in repository https://gitbox.apache.org/repos/asf/tomee.git
commit 464d7e04bac1a376e3f8e8621edb6165764f6c59
Author: Jean-Louis Monteiro <jl...@tomitribe.com>
AuthorDate: Mon Oct 30 15:29:04 2023 +0100
feat(#TOMEE-4268): MicroProfile OpenAPI Reader example.
---
examples/mp-openapi-reader/pom.xml | 127 +++++++++++++++++++
.../microprofile/openapi/CustomReader.java | 77 ++++++++++++
.../microprofile/openapi/WeatherService.java | 37 ++++++
.../microprofile/openapi/moviefun/Movie.java | 102 ++++++++++++++++
.../microprofile/openapi/moviefun/MoviesBean.java | 92 ++++++++++++++
.../openapi/moviefun/rest/ApplicationConfig.java | 34 ++++++
.../openapi/moviefun/rest/LoadRest.java | 41 +++++++
.../openapi/moviefun/rest/MoviesRest.java | 82 +++++++++++++
.../META-INF/microprofile-config.properties | 2 +
.../src/main/resources/META-INF/persistence.xml | 31 +++++
.../jakarta.servlet.ServletContainerInitializer | 1 +
.../src/main/webapp/WEB-INF/web.xml | 25 ++++
.../src/main/webapp/my-openapi.json | 25 ++++
.../src/main/webapp/openapi/openapi.yaml | 135 +++++++++++++++++++++
.../src/test/java/WeatherServiceTest.java | 95 +++++++++++++++
.../src/test/resources/arquillian.xml | 31 +++++
examples/pom.xml | 1 +
17 files changed, 938 insertions(+)
diff --git a/examples/mp-openapi-reader/pom.xml b/examples/mp-openapi-reader/pom.xml
new file mode 100644
index 0000000000..95ae07fc7e
--- /dev/null
+++ b/examples/mp-openapi-reader/pom.xml
@@ -0,0 +1,127 @@
+<?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.
+-->
+<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-openapi-reader</artifactId>
+ <version>10.0.0-SNAPSHOT</version>
+ <packaging>war</packaging>
+ <name>TomEE :: Examples :: Microprofile OpenAPI Reader</name>
+ <properties>
+ <version.jakartaee-api>9.1.1</version.jakartaee-api>
+ <version.arquillian.bom>1.7.0.Final</version.arquillian.bom>
+ <junit.version>4.13.2</junit.version>
+ <tomee.version>10.0.0-SNAPSHOT</tomee.version>
+ <version.microprofile.impl.openapi>3.0.1</version.microprofile.impl.openapi>
+ <version.openapi-api>3.1.1</version.openapi-api>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.tomee</groupId>
+ <artifactId>jakartaee-api</artifactId>
+ <version>${version.jakartaee-api}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.microprofile.openapi</groupId>
+ <artifactId>microprofile-openapi-api</artifactId>
+ <version>${version.openapi-api}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.smallrye</groupId>
+ <artifactId>smallrye-open-api</artifactId>
+ <version>${version.microprofile.impl.openapi}</version>
+ <scope>provided</scope>
+ <type>pom</type>
+ </dependency>
+ <dependency>
+ <groupId>io.smallrye</groupId>
+ <artifactId>smallrye-open-api-core</artifactId>
+ <version>${version.microprofile.impl.openapi}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>${junit.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tomee</groupId>
+ <artifactId>openejb-cxf-rs</artifactId>
+ <version>${tomee.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.arquillian.junit</groupId>
+ <artifactId>arquillian-junit-container</artifactId>
+ <version>${version.arquillian.bom}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tomee</groupId>
+ <artifactId>arquillian-tomee-remote</artifactId>
+ <version>${tomee.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tomee</groupId>
+ <artifactId>apache-tomee</artifactId>
+ <version>${tomee.version}</version>
+ <type>zip</type>
+ <classifier>microprofile</classifier>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.tomee.maven</groupId>
+ <artifactId>tomee-maven-plugin</artifactId>
+ <version>${tomee.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>
+ <!-- This section allows you to configure where to publish libraries for
+ sharing. It is not required and may be deleted. For more information see:
+ http://maven.apache.org/plugins/maven-deploy-plugin/ -->
+ <distributionManagement>
+ <repository>
+ <id>localhost</id>
+ <url>file://${basedir}/target/repo/</url>
+ </repository>
+ <snapshotRepository>
+ <id>localhost</id>
+ <url>file://${basedir}/target/snapshot-repo/</url>
+ </snapshotRepository>
+ </distributionManagement>
+</project>
diff --git a/examples/mp-openapi-reader/src/main/java/org/superbiz/microprofile/openapi/CustomReader.java b/examples/mp-openapi-reader/src/main/java/org/superbiz/microprofile/openapi/CustomReader.java
new file mode 100644
index 0000000000..2dc481d838
--- /dev/null
+++ b/examples/mp-openapi-reader/src/main/java/org/superbiz/microprofile/openapi/CustomReader.java
@@ -0,0 +1,77 @@
+package org.superbiz.microprofile.openapi;
+
+import io.smallrye.openapi.api.OpenApiConfig;
+import io.smallrye.openapi.api.OpenApiConfigImpl;
+import io.smallrye.openapi.api.OpenApiDocument;
+import io.smallrye.openapi.runtime.OpenApiProcessor;
+import io.smallrye.openapi.runtime.OpenApiStaticFile;
+import io.smallrye.openapi.runtime.io.Format;
+import jakarta.servlet.ServletContainerInitializer;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletException;
+import org.eclipse.microprofile.config.ConfigProvider;
+import org.eclipse.microprofile.openapi.OASModelReader;
+import org.eclipse.microprofile.openapi.models.OpenAPI;
+
+import java.net.URL;
+import java.util.Optional;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import static io.smallrye.openapi.runtime.io.Format.JSON;
+import static io.smallrye.openapi.runtime.io.Format.YAML;
+
+public class CustomReader implements OASModelReader, ServletContainerInitializer {
+
+ private static final Logger LOGGER = Logger.getLogger(CustomReader.class.getName());
+
+ private static Optional<OpenAPI> openAPI;
+
+ @Override
+ public OpenAPI buildModel() {
+ return openAPI.orElseThrow(() -> new IllegalStateException("OpenAPI document not available."));
+ }
+
+ @Override
+ public void onStartup(final Set<Class<?>> c, final ServletContext ctx) throws ServletException {
+ try {
+ final OpenApiConfig openApiConfig = new OpenApiConfigImpl(ConfigProvider.getConfig());;
+ final Optional<OpenAPI> yaml = readOpenApiFile(ctx, "/WEB-INF/classes/openapi/openapi.yaml", YAML);
+ final Optional<OpenAPI> json = readOpenApiFile(ctx, "/WEB-INF/classes/my-openapi.json", JSON);
+
+ final OpenApiDocument document = OpenApiDocument.INSTANCE;
+ try {
+ document.reset();
+ document.config(openApiConfig);
+ yaml.ifPresent(document::modelFromStaticFile);
+ json.ifPresent(document::modelFromStaticFile);
+ document.initialize();
+
+ openAPI = Optional.ofNullable(document.get());
+
+ } finally {
+ document.reset();
+ }
+
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static Optional<OpenAPI> readOpenApiFile(
+ final ServletContext servletContext, final String location,
+ final Format format) throws Exception {
+
+ final URL resource = servletContext.getResource(location);
+ if (resource == null) {
+ LOGGER.fine("Could not find static OpenAPI file " + location);
+ return Optional.empty();
+ }
+
+ LOGGER.fine("Found static OpenAPI file " + location);
+
+ try (OpenApiStaticFile staticFile = new OpenApiStaticFile(resource.openStream(), format)) {
+ return Optional.of(OpenApiProcessor.modelFromStaticFile(staticFile));
+ }
+ }
+}
diff --git a/examples/mp-openapi-reader/src/main/java/org/superbiz/microprofile/openapi/WeatherService.java b/examples/mp-openapi-reader/src/main/java/org/superbiz/microprofile/openapi/WeatherService.java
new file mode 100644
index 0000000000..bc6df1889d
--- /dev/null
+++ b/examples/mp-openapi-reader/src/main/java/org/superbiz/microprofile/openapi/WeatherService.java
@@ -0,0 +1,37 @@
+package org.superbiz.microprofile.openapi; /**
+ * 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.
+ */
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+
+@Path("/weather")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+@ApplicationScoped
+public class WeatherService {
+
+ @Path("/day/status")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String dayStatus() {
+ return "Hi, today is a sunny day!";
+ }
+}
diff --git a/examples/mp-openapi-reader/src/main/java/org/superbiz/microprofile/openapi/moviefun/Movie.java b/examples/mp-openapi-reader/src/main/java/org/superbiz/microprofile/openapi/moviefun/Movie.java
new file mode 100644
index 0000000000..5bf8264317
--- /dev/null
+++ b/examples/mp-openapi-reader/src/main/java/org/superbiz/microprofile/openapi/moviefun/Movie.java
@@ -0,0 +1,102 @@
+/**
+ * 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.
+ */
+package org.superbiz.microprofile.openapi.moviefun;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.xml.bind.annotation.XmlRootElement;
+
+@Entity
+@XmlRootElement(name = "movie")
+public class Movie {
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private long id;
+
+ private String director;
+ private String title;
+ private int year;
+ private String genre;
+ private int rating;
+
+ public Movie() {
+ }
+
+ public Movie(String title, String director, String genre, int rating, int year) {
+ this.director = director;
+ this.title = title;
+ this.year = year;
+ this.genre = genre;
+ this.rating = rating;
+ }
+
+ public Movie(String director, String title, int year) {
+ this.director = director;
+ this.title = title;
+ this.year = year;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getDirector() {
+ return director;
+ }
+
+ public void setDirector(String director) {
+ this.director = director;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public int getYear() {
+ return year;
+ }
+
+ public void setYear(int year) {
+ this.year = year;
+ }
+
+ public String getGenre() {
+ return genre;
+ }
+
+ public void setGenre(String genre) {
+ this.genre = genre;
+ }
+
+ public int getRating() {
+ return rating;
+ }
+
+ public void setRating(int rating) {
+ this.rating = rating;
+ }
+}
\ No newline at end of file
diff --git a/examples/mp-openapi-reader/src/main/java/org/superbiz/microprofile/openapi/moviefun/MoviesBean.java b/examples/mp-openapi-reader/src/main/java/org/superbiz/microprofile/openapi/moviefun/MoviesBean.java
new file mode 100644
index 0000000000..803e53f40c
--- /dev/null
+++ b/examples/mp-openapi-reader/src/main/java/org/superbiz/microprofile/openapi/moviefun/MoviesBean.java
@@ -0,0 +1,92 @@
+/**
+ * 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.
+ */
+package org.superbiz.microprofile.openapi.moviefun;
+
+import jakarta.ejb.Stateless;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.PersistenceContext;
+import jakarta.persistence.TypedQuery;
+import jakarta.persistence.criteria.CriteriaBuilder;
+import jakarta.persistence.criteria.CriteriaQuery;
+import jakarta.persistence.criteria.Path;
+import jakarta.persistence.criteria.Predicate;
+import jakarta.persistence.criteria.Root;
+import jakarta.persistence.metamodel.EntityType;
+
+import java.util.List;
+
+@Stateless
+public class MoviesBean {
+
+ @PersistenceContext(unitName = "movie-unit")
+ private EntityManager entityManager;
+
+ public Movie find(Long id) {
+ return entityManager.find(Movie.class, id);
+ }
+
+ public void addMovie(Movie movie) {
+ entityManager.persist(movie);
+ }
+
+ public void editMovie(Movie movie) {
+ entityManager.merge(movie);
+ }
+
+ public void deleteMovie(long id) {
+ Movie movie = entityManager.find(Movie.class, id);
+ entityManager.remove(movie);
+ }
+
+ public List<Movie> getMovies(Integer firstResult, Integer maxResults, String field, String searchTerm) {
+ CriteriaBuilder qb = entityManager.getCriteriaBuilder();
+ CriteriaQuery<Movie> cq = qb.createQuery(Movie.class);
+ Root<Movie> root = cq.from(Movie.class);
+ EntityType<Movie> type = entityManager.getMetamodel().entity(Movie.class);
+ if (field != null && searchTerm != null && !"".equals(field.trim()) && !"".equals(searchTerm.trim())) {
+ Path<String> path = root.get(type.getDeclaredSingularAttribute(field.trim(), String.class));
+ Predicate condition = qb.like(path, "%" + searchTerm.trim() + "%");
+ cq.where(condition);
+ }
+ TypedQuery<Movie> q = entityManager.createQuery(cq);
+ if (maxResults != null) {
+ q.setMaxResults(maxResults);
+ }
+ if (firstResult != null) {
+ q.setFirstResult(firstResult);
+ }
+ return q.getResultList();
+ }
+
+ public int count(String field, String searchTerm) {
+ CriteriaBuilder qb = entityManager.getCriteriaBuilder();
+ CriteriaQuery<Long> cq = qb.createQuery(Long.class);
+ Root<Movie> root = cq.from(Movie.class);
+ EntityType<Movie> type = entityManager.getMetamodel().entity(Movie.class);
+ cq.select(qb.count(root));
+ if (field != null && searchTerm != null && !"".equals(field.trim()) && !"".equals(searchTerm.trim())) {
+ Path<String> path = root.get(type.getDeclaredSingularAttribute(field.trim(), String.class));
+ Predicate condition = qb.like(path, "%" + searchTerm.trim() + "%");
+ cq.where(condition);
+ }
+ return entityManager.createQuery(cq).getSingleResult().intValue();
+ }
+
+ public void clean() {
+ entityManager.createQuery("delete from Movie").executeUpdate();
+ }
+}
\ No newline at end of file
diff --git a/examples/mp-openapi-reader/src/main/java/org/superbiz/microprofile/openapi/moviefun/rest/ApplicationConfig.java b/examples/mp-openapi-reader/src/main/java/org/superbiz/microprofile/openapi/moviefun/rest/ApplicationConfig.java
new file mode 100644
index 0000000000..625515c3fe
--- /dev/null
+++ b/examples/mp-openapi-reader/src/main/java/org/superbiz/microprofile/openapi/moviefun/rest/ApplicationConfig.java
@@ -0,0 +1,34 @@
+/**
+ * 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.
+ */
+package org.superbiz.microprofile.openapi.moviefun.rest;
+
+import jakarta.ws.rs.ApplicationPath;
+import jakarta.ws.rs.core.Application;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+@ApplicationPath("/rest")
+public class ApplicationConfig extends Application {
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Set<Class<?>> getClasses() {
+ return new HashSet<Class<?>>(Arrays.asList(LoadRest.class, MoviesRest.class));
+ }
+}
\ No newline at end of file
diff --git a/examples/mp-openapi-reader/src/main/java/org/superbiz/microprofile/openapi/moviefun/rest/LoadRest.java b/examples/mp-openapi-reader/src/main/java/org/superbiz/microprofile/openapi/moviefun/rest/LoadRest.java
new file mode 100644
index 0000000000..2d5d1e6e67
--- /dev/null
+++ b/examples/mp-openapi-reader/src/main/java/org/superbiz/microprofile/openapi/moviefun/rest/LoadRest.java
@@ -0,0 +1,41 @@
+/**
+ * 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.
+ */
+package org.superbiz.microprofile.openapi.moviefun.rest;
+
+import jakarta.ejb.EJB;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import org.superbiz.microprofile.openapi.moviefun.Movie;
+import org.superbiz.microprofile.openapi.moviefun.MoviesBean;
+
+@Path("load")
+public class LoadRest {
+ @EJB
+ private MoviesBean moviesBean;
+
+ @POST
+ public void load() {
+ moviesBean.addMovie(new Movie("Wedding Crashers", "David Dobkin", "Comedy", 7, 2005));
+ moviesBean.addMovie(new Movie("Starsky & Hutch", "Todd Phillips", "Action", 6, 2004));
+ moviesBean.addMovie(new Movie("Shanghai Knights", "David Dobkin", "Action", 6, 2003));
+ moviesBean.addMovie(new Movie("I-Spy", "Betty Thomas", "Adventure", 5, 2002));
+ moviesBean.addMovie(new Movie("The Royal Tenenbaums", "Wes Anderson", "Comedy", 8, 2001));
+ moviesBean.addMovie(new Movie("Zoolander", "Ben Stiller", "Comedy", 6, 2001));
+ moviesBean.addMovie(new Movie("Shanghai Noon", "Tom Dey", "Comedy", 7, 2000));
+ }
+
+}
\ No newline at end of file
diff --git a/examples/mp-openapi-reader/src/main/java/org/superbiz/microprofile/openapi/moviefun/rest/MoviesRest.java b/examples/mp-openapi-reader/src/main/java/org/superbiz/microprofile/openapi/moviefun/rest/MoviesRest.java
new file mode 100644
index 0000000000..80d2e889bf
--- /dev/null
+++ b/examples/mp-openapi-reader/src/main/java/org/superbiz/microprofile/openapi/moviefun/rest/MoviesRest.java
@@ -0,0 +1,82 @@
+/**
+ * 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.
+ */
+package org.superbiz.microprofile.openapi.moviefun.rest;
+
+import jakarta.ejb.EJB;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.DELETE;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.PUT;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.core.MediaType;
+import org.superbiz.microprofile.openapi.moviefun.Movie;
+import org.superbiz.microprofile.openapi.moviefun.MoviesBean;
+
+import java.util.List;
+
+@Path("movies")
+@Produces({"application/json"})
+public class MoviesRest {
+
+ @EJB
+ private MoviesBean service;
+
+ @GET
+ @Path("{id}")
+ public Movie find(@PathParam("id") Long id) {
+ return service.find(id);
+ }
+
+ @GET
+ public List<Movie> getMovies(@QueryParam("first") Integer first, @QueryParam("max") Integer max,
+ @QueryParam("field") String field, @QueryParam("searchTerm") String searchTerm) {
+ return service.getMovies(first, max, field, searchTerm);
+ }
+
+ @POST
+ @Consumes("application/json")
+ public Movie addMovie(Movie movie) {
+ service.addMovie(movie);
+ return movie;
+ }
+
+ @PUT
+ @Path("{id}")
+ @Consumes("application/json")
+ public Movie editMovie(Movie movie) {
+ service.editMovie(movie);
+ return movie;
+ }
+
+ @DELETE
+ @Path("{id}")
+ public void deleteMovie(@PathParam("id") long id) {
+ service.deleteMovie(id);
+ }
+
+ @GET
+ @Path("count")
+ @Produces(MediaType.TEXT_PLAIN)
+ public int count(@QueryParam("field") String field, @QueryParam("searchTerm") String searchTerm) {
+ return service.count(field, searchTerm);
+ }
+
+}
\ No newline at end of file
diff --git a/examples/mp-openapi-reader/src/main/resources/META-INF/microprofile-config.properties b/examples/mp-openapi-reader/src/main/resources/META-INF/microprofile-config.properties
new file mode 100644
index 0000000000..268e2ad12c
--- /dev/null
+++ b/examples/mp-openapi-reader/src/main/resources/META-INF/microprofile-config.properties
@@ -0,0 +1,2 @@
+mp.openapi.model.reader=org.superbiz.microprofile.openapi.CustomReader
+mp.openapi.scan.disable=false
diff --git a/examples/mp-openapi-reader/src/main/resources/META-INF/persistence.xml b/examples/mp-openapi-reader/src/main/resources/META-INF/persistence.xml
new file mode 100644
index 0000000000..ec38aaa117
--- /dev/null
+++ b/examples/mp-openapi-reader/src/main/resources/META-INF/persistence.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+<persistence version="2.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_2_0.xsd">
+ <persistence-unit name="movie-unit">
+ <jta-data-source>movieDatabase</jta-data-source>
+ <non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
+ <class>org.superbiz.moviefun.Movie</class>
+
+ <properties>
+ <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
+ </properties>
+ </persistence-unit>
+</persistence>
diff --git a/examples/mp-openapi-reader/src/main/resources/META-INF/services/jakarta.servlet.ServletContainerInitializer b/examples/mp-openapi-reader/src/main/resources/META-INF/services/jakarta.servlet.ServletContainerInitializer
new file mode 100644
index 0000000000..d0eefa40f3
--- /dev/null
+++ b/examples/mp-openapi-reader/src/main/resources/META-INF/services/jakarta.servlet.ServletContainerInitializer
@@ -0,0 +1 @@
+org.superbiz.microprofile.openapi.CustomReader
\ No newline at end of file
diff --git a/examples/mp-openapi-reader/src/main/webapp/WEB-INF/web.xml b/examples/mp-openapi-reader/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000000..6e1611111f
--- /dev/null
+++ b/examples/mp-openapi-reader/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,25 @@
+<?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 OpenAPI Reader</display-name>
+</web-app>
diff --git a/examples/mp-openapi-reader/src/main/webapp/my-openapi.json b/examples/mp-openapi-reader/src/main/webapp/my-openapi.json
new file mode 100644
index 0000000000..21cefed376
--- /dev/null
+++ b/examples/mp-openapi-reader/src/main/webapp/my-openapi.json
@@ -0,0 +1,25 @@
+{
+ "openapi" : "3.0.3",
+ "info" : {
+ "title" : "Generated API",
+ "version" : "1.0"
+ },
+ "paths" : {
+ "/rest/weather/day/status" : {
+ "get" : {
+ "responses" : {
+ "200" : {
+ "description" : "OK",
+ "content" : {
+ "text/plain" : {
+ "schema" : {
+ "type" : "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/mp-openapi-reader/src/main/webapp/openapi/openapi.yaml b/examples/mp-openapi-reader/src/main/webapp/openapi/openapi.yaml
new file mode 100644
index 0000000000..53fb4a7fe9
--- /dev/null
+++ b/examples/mp-openapi-reader/src/main/webapp/openapi/openapi.yaml
@@ -0,0 +1,135 @@
+---
+openapi: 3.0.3
+info:
+ title: Generated API
+ version: "1.0"
+paths:
+ /rest/load:
+ post:
+ responses:
+ "201":
+ description: Created
+ /rest/movies:
+ get:
+ parameters:
+ - name: field
+ in: query
+ schema:
+ type: string
+ - name: first
+ in: query
+ schema:
+ format: int32
+ type: integer
+ - name: max
+ in: query
+ schema:
+ format: int32
+ type: integer
+ - name: searchTerm
+ in: query
+ schema:
+ type: string
+ responses:
+ "200":
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Movie'
+ post:
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Movie'
+ responses:
+ "200":
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Movie'
+ /rest/movies/count:
+ get:
+ parameters:
+ - name: field
+ in: query
+ schema:
+ type: string
+ - name: searchTerm
+ in: query
+ schema:
+ type: string
+ responses:
+ "200":
+ description: OK
+ content:
+ text/plain:
+ schema:
+ format: int32
+ type: integer
+ /rest/movies/{id}:
+ get:
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ format: int64
+ type: integer
+ responses:
+ "200":
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Movie'
+ put:
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Movie'
+ responses:
+ "200":
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Movie'
+ delete:
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ format: int64
+ type: integer
+ responses:
+ "204":
+ description: No Content
+components:
+ schemas:
+ Movie:
+ type: object
+ properties:
+ id:
+ format: int64
+ type: integer
+ director:
+ type: string
+ title:
+ type: string
+ year:
+ format: int32
+ type: integer
+ genre:
+ type: string
+ rating:
+ format: int32
+ type: integer
+ xml:
+ name: movie
\ No newline at end of file
diff --git a/examples/mp-openapi-reader/src/test/java/WeatherServiceTest.java b/examples/mp-openapi-reader/src/test/java/WeatherServiceTest.java
new file mode 100644
index 0000000000..01e717c799
--- /dev/null
+++ b/examples/mp-openapi-reader/src/test/java/WeatherServiceTest.java
@@ -0,0 +1,95 @@
+/**
+ * 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.
+ */
+
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.WebTarget;
+import jakarta.ws.rs.core.Response;
+import org.apache.openejb.loader.IO;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.superbiz.microprofile.openapi.CustomReader;
+import org.superbiz.microprofile.openapi.WeatherService;
+import org.superbiz.microprofile.openapi.moviefun.Movie;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+@RunWith(Arquillian.class)
+public class WeatherServiceTest {
+
+ @Deployment(testable = false)
+ public static WebArchive createDeployment() {
+ final WebArchive webArchive = ShrinkWrap.create(WebArchive.class, "test.war")
+ .addClass(WeatherService.class)
+ .addClass(CustomReader.class)
+ .addPackages(true, Movie.class.getPackage())
+ .addAsResource("META-INF/services/jakarta.servlet.ServletContainerInitializer")
+ .addAsResource("META-INF/persistence.xml")
+ .addAsResource("META-INF/microprofile-config.properties")
+ .addAsResource(new File("src/main/webapp/my-openapi.json"), "my-openapi.json")
+ .addAsResource(new File("src/main/webapp/openapi/openapi.yaml"), "openapi/openapi.yaml")
+ .addAsWebInfResource(new StringAsset("<beans/>"), "beans.xml");
+ return webArchive;
+ }
+
+ @ArquillianResource
+ private URL base;
+
+ private Client client;
+
+ @Before
+ public void before() {
+ this.client = ClientBuilder.newClient();
+ }
+
+ @After
+ public void after() {
+ this.client.close();
+ }
+
+ @Test
+ public void openapi() throws IOException {
+ final WebTarget webTarget = client.target(base.toExternalForm());
+
+ final Response response = webTarget.path("/openapi")
+ .request()
+ .accept("application/json")
+ .buildGet().invoke();
+ final InputStream entity = (InputStream) response.getEntity();
+ final String payload = IO.slurp(entity);
+
+ // assert that it returns a payload
+ Assert.assertNotNull(payload);
+
+ // now check if the 2 openapi documents (yaml and json) got successfully loaded and merged
+ Assert.assertTrue(payload.contains("/rest/weather/day/status")); // from one openapi file
+ Assert.assertTrue(payload.contains("/rest/movies")); // from the other one
+ }
+
+}
diff --git a/examples/mp-openapi-reader/src/test/resources/arquillian.xml b/examples/mp-openapi-reader/src/test/resources/arquillian.xml
new file mode 100644
index 0000000000..0b54540a34
--- /dev/null
+++ b/examples/mp-openapi-reader/src/test/resources/arquillian.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+
+ 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.
+-->
+<arquillian xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+
+ <container qualifier="tomee" default="true">
+ <configuration>
+ <property name="httpPort">-1</property>
+ <property name="stopPort">-1</property>
+ <property name="debug">false</property>
+ <property name="classifier">microprofile</property>
+ <property name="dir">target/apache-tomee-remote</property>
+ <property name="appWorkingDir">target/arquillian-test-working-dir</property>
+ </configuration>
+ </container>
+</arquillian>
\ No newline at end of file
diff --git a/examples/pom.xml b/examples/pom.xml
index f126a11a8e..b5af5082d3 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -129,6 +129,7 @@
<module>mp-rest-jwt-public-key</module>
<module>mp-rest-client</module>
<module>mp-custom-healthcheck</module>
+ <module>mp-openapi-reader</module>
<module>mtom</module>
<module>multi-jpa-provider-testing</module>
<module>multiple-arquillian-adapters</module>