I created a dynamic java project and added this dependency:
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.containers/jersey-container-servlet-core -->
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<version>2.23.1</version>
</dependency>
Then i created the App class like this:
#ApplicationPath("/test")
public class App extends ResourceConfig {
public App() {
this.packages("com.test.ul");
}
}
and in the same package as the App class is in, i created this:
#Path("restaurantAPI")
public class RestaurantAPI {
#Path("/get")
#GET
public Response getRequest(#PathParam("id") String id) {
return Response.ok(id).build();
}
}
I run my server, and I call this URL:
http://localhost:8080/ULTestServer/test/restaurantAPI/get?id=3
but I get error 404
What Am I missing please ? (I always do that and it used to work)
Change
jersey-container-servlet-core
to
jersey-container-servlet
The reason is that the latter has the required component1 that allows for discovering your application without web.xml, in replace for #ApplicationPath. This is part of the servlet 3 pluggability mechanism.
The first dependency is use for non servlet 3.0 containers, where the use would have to use a web.xml to register the Jersey servlet.
1 - Here is the implementation
Related
I have a Spring Boot application where the API is specified as a OpenAPI 3.0.2 YAML document. I used the openapi-generator-maven-plugin to generate code from the spec. When I open up http://localhost:8080/swagger-ui.html, it displays: "No operations defined in spec!"
In the spec, I have:
servers:
- url: /books/api/v1
Which results in this in the controller class:
#javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2021-06-17T14:52:43.686820-07:00[America/Los_Angeles]")
#Controller
#RequestMapping("${openapi.axmPlatformKeyService.base-path:/books/api/v1}")
public class SvcApiController implements SvcApi {
// ...
// ...
}
If I load the openapi-definition.yaml in editor.swagger.io, it shows the definitions as expected.
If I create another controller this way:
#RestController
public class AddonController implements SvcApi {
// ...
// ...
}
then Swagger UI shows the APIs, which basically means that if the generated code had "#RestController" it would have worked okay.
Since the generated controller is annotated with #Controller, Swagger UI is not able to pick it up. Even after adding this extra #RestController, Swagger UI's Try it out function doesn't include "/books/api/v1" in the URL it generates.
Net-effect is with this AddonController, if I have one request /book/{id} in the spec, there are two endpoints in the service:
/books/api/v1/book/{id}
/book/{id}
and the latter is invoked by Swagger UI.
These are the relevant dependencies:
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.5.0</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.6.2</version>
</dependency>
Adding a static initializer that does
SpringDocUtils.getConfig().addRestControllers(SvcApiController.class)
resolves the issue. The AddonController is not needed in this case.
Edit: I uploaded a minimal example. You can build with mvn clean install and after deployment, open the following urls:
http://localhost:8080/jaxrs-test/unqualified -> response: Hello there: de.test.SomeBean#........
http://localhost:8080/jaxrs-test/qualified -> response: Hello there: null
Tested on wildfly-23.0.0.Final with openjdk11.
Original quesion:
Consider the classes:
App.java - Jaxrs application:
#ApplicationPath("/api")
public class App extends Application {
}
Q.java - qualifier annotation:
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface Q {
}
X.java - some simple class:
public class X {
public String getX(){
return "some x";
}
}
Foo.java - jaxrs resource:
#Path("/foo")
#Q
public class Foo {
#Inject
private X test;
#Path("bar")
#GET
public String getBar() {
return test.getX();
}
}
The pom contains the following dependencies (and nothing else relevant):
<dependencies>
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.1.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
After building this application and deploying it to a wildfly server, a reques to
http://localhost:8080/app/api/foo/bar
leads to a null pointer exception, because test in the Foo resource is null.
The request and injection of X works perfectly when removing the qualifier annotation.
Why is that? I could not find anything in the documentation suggesting that.
Is there any way to get CDI working in a qualified jaxrs-resource class?
With qualified I mean any qualifier besides #Named, since the latter does not prevent the class to get the qualifier #Default.
So I've started setting up a simple SparkJava application from scratch with the basic goal of comparing it to a mirrored SpringBoot (with SpringData) application which I've already built. However I've been struggling with DeltaSpike (which is the alternative to SpringData chosen) setup as that adds a layer of CDI complexity which I didn't have to handle within SpringBoot.
Long story short after trying out some (probably wrong) approaches: now I'm stuck at enabling Weld (CDI) in the SparkJava Jetty container. I've taken a look on how to enable Weld for Jetty but that only got me more confused - and I'm not even sure that it's supposed to work.
What I'm getting now is: Exception in thread "main" java.lang.NoClassDefFoundError: org/jboss/weld/events/WeldEvent.
Since there are many files it's better to just share my github repo: https://github.com/vitorbmiranda/taskapp-sparkjava. Don't mind unused code and stuff like that as it's still a WIP.
A final disclaimer: apart from that error itself I feel like I may be completely missing something or my approach with SparkJava/CDI/DeltaSpike could be completely off, or my Maven dependencies could not make any sense, so any directions on that would also be appreciated. Cheers.
Update Sep 2nd: did a fresh setup on a new repo. Managed to customize the Spark embedded Jetty handler and added the Weld Listener to it.
This is how I've added the listeners:
import org.jboss.weld.environment.servlet.BeanManagerResourceBindingListener;
import org.jboss.weld.environment.servlet.Listener;
...
JettyHandler handler = new JettyHandler(matcherFilter);
...
handler.addEventListener(new BeanManagerResourceBindingListener());
handler.addEventListener(new Listener());
This is from the startup log (using TRACE level within logback.xml)
5:46:50.427 [Thread-0] DEBUG o.e.j.u.component.ContainerLifeCycle - spark.embeddedserver.jetty.JettyHandler1530180168==dftMaxIdleSec=-1 added {org.jboss.weld.environment.servlet.BeanManagerResourceBindingListener#49483272,UNMANAGED}
15:46:50.432 [Thread-0] DEBUG o.e.j.u.component.ContainerLifeCycle - spark.embeddedserver.jetty.JettyHandler1530180168==dftMaxIdleSec=-1 added {org.jboss.weld.environment.servlet.Listener#62383f62,UNMANAGED}
No "Weld" references after that. If I try to use any #Injected bean it won't work as expected (since logs didn't give me anything related to Bean/classpath lookup):
public class TestController {
#Inject
TestService testService;
public static String getTest(Request request, Response response) {
// NPE here
testService.test();
return value;
}
}
#Default
public class TestService {
public String test() {
return "123";
}
}
My pom.xml looks like:
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-core</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se-core</artifactId>
<version>3.1.2.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.weld.servlet</groupId>
<artifactId>weld-servlet-core</artifactId>
<version>3.1.2.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.weld</groupId>
<artifactId>weld-spi</artifactId>
<version>3.1.SP1</version>
</dependency>
The META-INF/beans.xml (which I would think it's not necessary, anyway) is:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="all">
</beans>
I work on spring boot 1.3.3.RELEASE with JSP as view technology.
JSP pages , static resources like CSS, JS and images are loading properly. But how to serve static resource like txt or xml (robots.txt, sitemap.xml)
My controller is handling the request and trying to render jsp view.
Application.java
#SpringBootApplication
public class SampleWebJspApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SampleWebJspApplication.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(SampleWebJspApplication.class, args);
}
}
Controller
#Controller
public class WelcomeController {
#RequestMapping(value = "/{name}")
public String welcome(#PathVariable String name) {
return name;
}
}
application.properties
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
Following URL's handled by controller and it renders home.jsp
/home
/home.css
/home.js
/home.txt
/home.xml
Following URL's Not working
/home.jsp - 404
/robots.txt - 404 - trying to render robots.jsp
/sitemap.xml - 404 - trying to render sitemap.jsp
Spring-Boot doesnt do jsp's anymore, they are trying to force you to use thymeleaf or another templating engine, static resources are available from certain directories. /static is one of them. and the thymeleaf files need to be in a templates folder.
My setup on my latest spring boot is as follows
application/src/main/resources/static
/templates
application.properties
for other ones you need to add a resourcehandler for the other locations /robots.txt etc
Jsp still works with spring boot.
Not sure if you already did this but its important that you add these dependencies to your maven or gradle.
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
You have configured the Spring's View Resolver with this line spring.mvc.view.prefix , so every response returned by your controllers , will be chained to the view Resolver , which will try to find the resource under /WEB_INF/JSP based on the string name you returned(not sure if you have placed this folder under resources , as your app is a spring boot one , not a java web app). In order to do that and keep the view resolver , either wire up another servlet to share static resources or wire up a ResourcesController with default locations. Something like :
#Configuration
public class StaticResourceConfiguration extends WebMvcConfigurerAdapter {
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
"classpath:/myStaticResources/", "classpath:/static/" };
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS);
}
}
More info here or here
Also Spring boot gives you this way as well :
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/
More info about the application properties here
The important part is: without web.xml.
I already have a working JAX-RS app running on Glassfish 3.1.2.2 without a web.xml, configured purely by annotations.
The question is, how can I maintain the web.xml-less nirvana and still use Jersey MVC to serve static resources from the resources or webapp directory of my Maven .war project?
I see in many answers how can I do this with web.xml configuration, but nobody mentions how to map resources without the web.xml file.
Currently I have a ui.html file under the resources directory, a JAX-RS Application subclass and a resource class. No web.xml in the project and the following is working well:
#Path("/ui")
#GET
public Response ui() {
String content = "Hello StackOverflow";
return Response.ok(content).build();
}
While this one is failing with the IOException from the resolver:
#Path("/ui")
#GET
public Response ui() {
Viewable viewable = new Viewable("/ui.html");
return Response.ok(viewable).build();
}
java.io.IOException: The template name, /ui.html, could not be resolved to a fully qualified template name
I also tried to specify it with a relative path, but that didn't work either.
The dependencies I'm using for Jersey are as follows:
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.18</version>
</dependency>
I understand that a proper example project would be the best and willing to provide that if people are having a hard time figuring out what I'm talking about, just let me know.
Peter Metz, I believe this is possible by using the #WebFilter annotation on a class that extends org.glassfish.jersey.servlet.ServletContainer (Jersey 2.26):-
package com.myorg.myapp.config;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import org.glassfish.jersey.servlet.ServletContainer;
#WebFilter(value = "/*", initParams = #WebInitParam(name = "javax.ws.rs.Application", value = "com.myorg.myapp.config.JerseyConfig"))
public class JerseyFilter extends ServletContainer {
private static final long serialVersionUID = 1L;
}