Getting swagger-core 1.5 to work with Jersey and Grizzly - jersey-2.0

I have a Jersey2 application that runs on an embedded Grizzly server - a setup identical to this example:
https://github.com/jersey/jersey/tree/2.18/examples/https-clientserver-grizzly/src/main/java/org/glassfish/jersey/examples/httpsclientservergrizzly
I have integrated it with swagger-jersey2-jaxrs_2.10 and it has been working OK.
Now that swagger-core 1.5 came out and it produces Swagger 2.0 definitions, I would like to upgrade to that version.
Having followed the Swagger setup instructions from this site:
https://github.com/swagger-api/swagger-core/wiki/Swagger-Core-Jersey-2.X-Project-Setup-1.5
I discovered that Swagger won't work any more as it requires a ServletContext instance to be injected,
and ServletContext fields annotated with #Context are not being injected in my project (they show as nulls).
So my actual question is: does jersey-container-grizzly2-servlet support ServletContext at all?
Is there any way I can get ServletContext to be injected by altering my project's config?
Or should I look into ways of integrating swagger-core 1.5 that don't require a ServletContext?

This is how I got it working:
Add these dependencies to your pom.xml:
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-jersey2-jaxrs</artifactId>
<version>1.5.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-servlet</artifactId>
</dependency>
Register ApiListingResource and SwaggerSerializers:
#ApplicationPath("/")
public class MyApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<>();
classes.add(io.swagger.jaxrs.listing.ApiListingResource.class);
classes.add(io.swagger.jaxrs.listing.SwaggerSerializers.class);
return classes;
}
}
Initialize Grizzly, Jersey and Swagger:
public class Main
{
private final static Logger logger = LogManager.getLogger(Main.class);
public static final String BASE_URI = "http://0.0.0.0:8080";
public static HttpServer startServer()
{
BeanConfig beanConfig = new BeanConfig();
beanConfig.setVersion("1.0.2");
beanConfig.setBasePath("/");
beanConfig.setResourcePackage("your packages");
beanConfig.setScan(true);
HttpServer httpServer = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), new ResourceConfig());
// Initialize and register Jersey Servlet
WebappContext context = new WebappContext("WebappContext", "");
ServletRegistration registration = context.addServlet("ServletContainer", ServletContainer.class);
registration.setInitParameter("javax.ws.rs.Application", MyApplication.class.getName());
registration.addMapping("/*");
context.deploy(httpServer);
return httpServer;
}
public static void main(String[] args) throws Exception
{
startServer();
}
}

Related

Configuring the Batch Configurer to include transaction with Spring Data MongoDb in Spring Batch

In our application, we implemented Spring Data MongoDB transactions by following this guide
https://www.baeldung.com/spring-data-mongodb-transactions
However, we keep facing this issue.
I am unsure on how I should override the BatchConfigurer.
I have tried to follow this guide, but it uses an earlier version of Spring Data MongoDb. Some of the classes are deprecated
https://dzone.com/articles/spring-batch-goodies-with-mongodb
Error:
Description:
The bean 'transactionManager', defined in class path resource [org/springframework/batch/core/configuration/annotation/SimpleBatchConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [com/pragnamic/common/infrastructure/MongoDbConfig.class] and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
MongoDbConfig
#Configuration
public class MongoDbConfig extends AbstractMongoClientConfiguration {
private final List<Converter<?,?>> converters = new ArrayList<>();
#Value("${spring.data.mongodb.uri}")
private String uri;
#Value("${spring.data.mongodb.database}")
private String database;
#Bean
MongoTransactionManager transactionManager(MongoDatabaseFactory mongoDatabaseFactory) {
return new MongoTransactionManager(mongoDatabaseFactory);
}
#Override
protected String getDatabaseName() {
return database;
}
#Override
public MongoClient mongoClient() {
ConnectionString connectionString = new ConnectionString(uri);
MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
.applyConnectionString(connectionString)
.build();
return MongoClients.create(mongoClientSettings);
}
#Bean
public MongoCustomConversions customConversions() {
converters.add(new DomainObjectIdWriterConverter());
return new MongoCustomConversions(converters);
}
}
We are also using the latest version of Spring Data MongoDB
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

#Autowired are giving Null Pointer Exceptions in SpringBoot CXF application

I have created a SpringBoot CXF soap service from an existing WSDL file. I can now access WSDL from my service running on embedded tomcat from the springboot application. When I am trying to send a request to the service from soap-ui, the control reaches the implementation of the service method and then while it access the #Autowired service layer, it throws all NPE, as the service object is null (I have seen this while debugging). If I manually create (new Service() by commenting out the #Autowired object), the flow can reach the service implementation and then the DAO object fails as it cannot #Autowire the DAO Impl, further when i create the manually DAO Impl object it fails at #PersistenceContext, as it the entity manager is null.
I have made sure service is annotated with #Service, DAO layer with #Repository, still the issue persists. Also i have added #ComponentScan and giving all the package names, still i am getting null for all #Autowired.
Code below: Configuration class
#SpringBootApplication
public class EmWebSvcBootApplication extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(EmWebSvcBootApplication.class, args);
}
public static final String SERVICE_NAME_URL_PATH = "/em";
public static final String EM_ISSUER_SERVICE_NAME_URL_PATH = "/EntitlementIssuer";
#Bean(name=Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
return new SpringBus();
}
#Bean
public ServletRegistrationBean cxfServlet() {
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new CXFServlet(), SERVICE_NAME_URL_PATH + "/*");
// Add custom Title to CXF´s ServiceList
Map<String, String> initParameters = servletRegistrationBean.getInitParameters();
initParameters.put("service-list-title", "My Test service");
return servletRegistrationBean;
}
#Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(springBus(), new EntitlementIssuerEndpointImpl());
endpoint.setServiceName(entitlementIssuer_Service().getServiceName());
endpoint.setWsdlLocation(entitlementIssuer_Service().getWSDLDocumentLocation().toString());
endpoint.publish(EM_ISSUER_SERVICE_NAME_URL_PATH);
return endpoint;
}
#Bean EntitlementIssuer_Service entitlementIssuer_Service(){
return new EntitlementIssuer_Service();
}
}
Service class:
#Service
public class EntitlementIssuerServiceImpl implements EntitlementIssuerService {
private static final Logger logger = LoggerFactory.getLogger(EntitlementIssuerServiceImpl.class);
#Autowired
private EntitlementIssuerDAO entitlementIssuerDAO;
#Transactional(readOnly=true)
public List<EntitlementIssuerResponseWrapper> getEntitlementIssuers(EntitlementIssuerRequestWrapper requestWrapper)
throws EMSystemException, EMBusinessException {
try{
daoResponse = entitlementIssuerDAO.findEntitlementIssuers(requestWrapper);
}catch(Throwable t){
logger.error("Error while getting entitlement issuers: " + t.getMessage());
throw new EMSystemException("Error while getting entitlement issuers: " + t.getMessage());
}
}
DAO layer:
#Repository
public class EntitlementIssuerDaoImpl implements EntitlementIssuerDAO{
#PersistenceContext
private EntityManager entityManager;
public EntityManager getEntityManager() {
return entityManager;
}
#Override
public List<EntitlementIssuer> findEntitlementIssuers(EntitlementIssuerRequestWrapper request) {
Session session = (Session) entityManager.getDelegate();
Criteria criteria = session.createCriteria(EntitlementIssuer.class, "entitlementIssuer");
setupCriteria(request,criteria);
List<EntitlementIssuer> output = criteria.list();
return output;
}
}
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<em.wsdl.version>2.2.0</em.wsdl.version>
<cxf.version>3.1.7</cxf.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- Apache CXF -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
I have added all the configurations that i am using, any help to fix this is highly appreciated. Basically all the #Autowired services, data layers, and entity managers are not loaded (as i see them as null in the debug).
I have been able to fix the issue based on the info from https://github.com/codecentric/cxf-spring-boot-starter
/**
* Configuration of SOAP Web services
*/
#Configuration
public class EntitlementIssuerServiceSOAPConfig {
#Autowired
private Bus bus;
#Bean
public EntitlementIssuerService getEntitlementIssuerServiceWebServiceImpl() {
return new EntitlementIssuerServiceWebServiceImpl();
}
#Bean (name = "EntitlementIssuerServiceWebService")
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(bus, getEntitlementIssuerServiceWebServiceImpl());
endpoint.publish("/EntitlementIssuerService");
return endpoint;
}
}

NullPointerException when inject enterprise bean into JAX-RS 2.0 REST service

I am trying to inject and EJB 3.1 in one of my RESTful services. I've followed the post: Inject an EJB into JAX-RS (RESTful service) and tried all options except building an injection provider. The current solution that I am trying uses a combination of #RequestScoped and #Inject, but my injected bean variable is still null. I have a beans.xml in the /WEB-INF folder.
How can I inject an EJB into my REST service class?
UserService
#Local
#Path("user/v1")
#Produces(MediaType.APPLICATION_JSON)
public class UserServiceV1 implements SystemLogger {
#Inject
private ApplicationBean appBean;
#GET
#Path("pingbean")
#Produces(MediaType.APPLICATION_JSON)
public Response pingAppBean() {
if(appBean == null) {
return Response.status(Response.Status.UNAUTHORIZED).entity("{\"faild\": \"App bean is null\"}").build();
}
String message = appBean.getHello();
return Response.status(Response.Status.OK)
.entity(message)
.build();
}
}
ApplicationBean
The SystemHandler resides in jar module and is a standard class with business logic.
#Stateless
#Local
public class ApplicationBean implements ApplicationBeanLocal {
#Override
public String getHello() {
return "Hello from ApplicationBean";
};
}
JAX-RS configuration
#ApplicationPath("service")
public class ApplicationService extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new HashSet<>();
resources.add(UserServiceV1.class);
resources.add(ApplicationBean.class);
resources.add(CorsFilterProvider.class);
return resources;
}
}
Exception
14:07:01,230 ERROR [io.undertow.request] UT005023: Exception handling request to /MyApp/service/user/v1/login: org.jboss.resteasy.spi.UnhandledException: java.lang.NullPointerException
at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:76) [resteasy-jaxrs-3.0.14.Final.jar:3.0.14.Final]
at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:212) [resteasy-jaxrs-3.0.14.Final.jar:3.0.14.Final]
Resteasy /JAX-RS
I've added a CDI implementation for resteasy according to the documentation
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>3.0.14.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-cdi</artifactId>
<version>3.0.14.Final</version>
<scope>provided</scope>
</dependency>
EDIT: changed code details in the question and title
EJB 3.1 implies a Java EE 6 container implementation.
Java EE 6 implies JAX-RS 1.1.
JAX-RS 1.1 is only required to support #EJB injection of enterprise java beans.
JAX-RS 2.0 as provided in a Java EE 7 implementation supports #Inject for EJBs.
As Steve C answered, the proper way to inject an EJB in JAX-RS 1.1 is with the javax.ejb.EJB annotation. The REST service must also be an EJB for this to work. As such, you have to use the javax.ejb.Stateless annotation instead of javax.enterprise.context.RequestScoped.
The end result is as follows:
#Stateless
#Path("user/v1")
public class UserServiceV1 implements SystemLogger {
#EJB
private ApplicationBean appBean;
//etc.
}
EDIT
Your updated code doesn't deploy. Either have ApplicationBean implement ApplicationBeanLocal and inject the interface, or don't implement it and inject the class directly. With that corrected, I managed to run your example just fine.
Also, in ApplicationService, you don't need to add ApplicationBean.class. You only register there REST root resources and feature providers. #Local is also unnecessary in the UserServiceV1 class, it's not an EJB.
Furthermore, it's beans.xml, not bean.xml (but this file is not necessary anymore from CDI 1.1 on).
See my testcode below:
pom.xml dependencies for the jar module:
<dependencies>
<dependency>
<groupId>javax.ejb</groupId>
<artifactId>javax.ejb-api</artifactId>
<version>3.2</version>
</dependency>
</dependencies>
ApplicationBeanLocal.java:
public interface ApplicationBeanLocal {
String getHello();
}
ApplicationBean.java:
#Stateless
#Local
public class ApplicationBean implements ApplicationBeanLocal {
#Override
public String getHello() {
return "Hello from ApplicationBean";
}
}
pom.xml dependencies for the JAX-RS application:
<dependencies>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>3.0.14.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-cdi</artifactId>
<version>3.0.14.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>1.2</version>
<scope>provided</scope>
</dependency>
<!-- The jar-module containing ApplicationBean and ApplicationBeanLocal -->
<dependency>
<groupId>test</groupId>
<artifactId>testjar</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
TestApplication.java:
#ApplicationPath("service")
public class TestApplication extends Application {
private final Set<Class<?>> resources = new HashSet<>();
public TestApplication() {
resources.add(UserServiceV1.class);
}
#Override
public Set<Class<?>> getClasses() {
return resources;
}
}
UserServiceV1.java
#Path("user/v1")
#RequestScoped
#Produces(MediaType.APPLICATION_JSON)
public class UserServiceV1 {
#Inject // Note that I'm referencing the interface, not the implementation
private ApplicationBeanLocal appBean;
#GET
#Path("pingbean")
#Produces(MediaType.APPLICATION_JSON)
public Response pingAppBean() {
final String message = appBean.getHello();
return Response.status(Response.Status.OK).entity(message).build();
}
}

Why I cannot create endpoint with RestEasy

I'm trying to implement a test for my REST endpoint, described here: http://antoniogoncalves.org/2012/12/19/test-your-jax-rs-2-0-web-service-uris-without-mocks/. Mentioned solution uses Jersey implementation of JAX-RS, but I want to use RestEasy. When I run my test I get
java.lang.UnsupportedOperationException
at org.jboss.resteasy.spi.ResteasyProviderFactory.createEndpoint(ResteasyProviderFactory.java:2176)
Any idea why JBoss's implementation of JAX-RS does not support creating endpoints, but Jersey's does (as it is under the link from the beginning of my post)?
Take a look at the RESTeasy documentation, Chapter 36. Embedded Containers. You will find examples for four different types of containers and their usage in testing:
Undertow
Sun HttpServer
TJWS
Netty
You can pick your flavor.
Here's a complete example using the Sun HttpServer (as in the example you linked to):
public class SunHttpServerTest {
#Path("simple")
public static class SimpleResource {
#GET
public String get() {
return "Hello Sun";
}
}
private HttpContextBuilder contextBuilder;
private HttpServer httpServer;
#Before
public void setUp() throws Exception {
httpServer = HttpServer.create(new InetSocketAddress(8000), 10);
contextBuilder = new HttpContextBuilder();
contextBuilder.getDeployment().getActualResourceClasses().add(SimpleResource.class);
HttpContext context = contextBuilder.bind(httpServer);
context.getAttributes().put("some.config.info", "42");
httpServer.start();
}
#After
public void tearDown() {
contextBuilder.cleanup();
httpServer.stop(0);
}
#Test
public void shouldReturnCorrectMessage() {
Client client = ClientBuilder.newClient();
Response response = client.target("http://localhost:8000/simple")
.request().get();
assertEquals(200, response.getStatus());
String message = response.readEntity(String.class);
assertEquals("Hello Sun", message);
System.out.println(message);
response.close();
}
}
Also needed for this to work is the following dependency
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jdk-http</artifactId>
<version>3.0.9.Final</version>
</dependency>

How to used "web request by spring mvc" and "rest by jersey" in spring boot

Hi i want to handle web request by spring mvc and handle rest by jersey
in the same project (Spring-Boot)
As i test Rest service is working but web is not
How can i set Application Config ?
#SpringBootApplication
#EnableAutoConfiguration
#ComponentScan(basePackageClasses = {ProductsResource.class, MessageService.class,Web.class})
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
#Bean
public ServletRegistrationBean jerseyServlet() {
ServletRegistrationBean registration = new ServletRegistrationBean(new ServletContainer(), "/rest/*");
registration.addInitParameter(ServletProperties.JAXRS_APPLICATION_CLASS, JerseyInitialization.class.getName());
return registration;
}
#Bean
public ServletRegistrationBean webMVC() {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(ResourceConfig.class);
dispatcherServlet.setApplicationContext(applicationContext);
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(dispatcherServlet, "*.html");
servletRegistrationBean.setName("web-mvc");
return servletRegistrationBean;
}
Web Controller
#Controller
#Component
public class Web {
#RequestMapping("/foo")
String foo() {
return "foo";
}
#RequestMapping("/bar")
String bar() {
return "bar";
}
}
Rest Controller
#Path("/")
#Component
public class ProductsResource {
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/hello")
public String hello() {
return "Hello World";
}
}
Actually with spring boot (I'm talking about version 1.4.x), it's pretty easy to do Spring MVC and JAX-RS(rest by jersey) at the same time :). You don't need any servlet registrations. All you need to do is to add a Configuration class like the following
#Configuration
#ApplicationPath("/rest")
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
packages("your.package.with.rest.resources");
}
}
Now all your JAXRS resources are served under /rest/*
For example, your Rest Controller can be refactored as
#Path("/hello")
#Component
public class ProductsResource {
#GET
#Produces(MediaType.APPLICATION_JSON)
public String hello() {
return "Hello World";
}
}
Now if you hit url http://server:port/rest/hello, Hello World should be returned.
Finally, remember to add the following dependencies in your maven pom file
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
That should work for you.