I am still working on a jax-rs server, and I faced some new problems recently. I do not understand where I define the name of my webserver. I searched everything in my workspace, but couldn't find anything.
Let's roll out the problem a bit further:
I always reach my server's #GET method via http://XXXXXX.XXXXX.XXX-XXXXXXX.de/android/
This is the structure of my server class:
#Path("/users")
public class UserResource {
Connection dbconn = null;
public UserResource() {
userIds = new ArrayList<Integer>();
userIds.add(1);
userIds.add(2);
userIds.add(3);
}
#GET
#Path("/login/{id}")
#Consumes("application/xml")
public StreamingOutput getTests(#PathParam("id") int id, InputStream is) {
return new StreamingOutput() {
public void write(OutputStream outputStream) throws IOException,
WebApplicationException {
getTests(outputStream);
}
};
}
As you see, the path of my class is "/users", and the path of the #GET method is "/login/1" (for example id = 1). Now I tried to call the method via
http://XXXXXX.XXXXX.XXX-XXXXXXX.de/android/users/login/1
But this does not work. I get an error (unknown source). And my error.log says that it couldn't find the resource at
http://XXXXXX.XXXXX.XXX-XXXXXXX.de/users/users/login/1
My 1st question: Where does the double "/users" come from? I have no idea. When I leave away the "/users" in my request url, there will be only 1 "/users" in the error.log, but still the resource is not found.
And there is another thing I did not find out yet: How do I change the name of my service? Atm, it's "android", but how could I change this? I searched my whole workspace, found "android" in my pom.xml, but when i change it to, let's say "testandroid", upload everything, build and run the server, the name is still android. No idea why this is the case.
Thx for your help guys!
EDIT:
This is my "main" class:
package com.restfully.services;
import javax.ws.rs.core.Application;
import java.util.HashSet;
import java.util.Set;
public class ServerApplication extends Application {
private Set<Object> singletons = new HashSet<Object>();
private Set<Class<?>> empty = new HashSet<Class<?>>();
public ServerApplication() {
singletons.add(new UserResource());
}
#Override
public Set<Class<?>> getClasses() {
return empty;
}
#Override
public Set<Object> getSingletons() {
return singletons;
}
}
I am using Eclipse and Maven. The application runs on a jetty-server. If you could use any further information, let me know.
You can look in the following places
Pom.xml file for context root the following entry;
<configuration>
<context>yourWarName</context>
</configuration>
Using Netbeans check Run Category context path under project properties.
Context Path: /yourWarName
Have a look in your web.xml as well.
When using jax-rs you normally define a config class;
#ApplicationPath("resources")
public class RestConfig extends Application{
}
From there you define your other paths;
#Stateless
#Path("/login")
public class LoginResource
public Response login(Credentials credentials) {
Credentials result = this.loginService.login(credentials);
return Response.status(Response.Status.OK).entity(result).build();
}
The path to the following is: http://domain.com/MyApp/resources/login
where MyApp is the context root.
It might be that there is a path specified in config or root with the name users that you are getting the double users.
Related
I'd like to implement a simple REST-API with Jersey and grizzly. After beeing stuck in dependency-hell for a while, I ended up with an exception and I have no idea how to handle/interpret:
java.lang.IllegalArgumentException: The implementation class org.glassfish.jersey.inject.hk2.RequestContext must be in the Singleton scope
at org.jvnet.hk2.internal.ServiceLocatorImpl.checkConfiguration(ServiceLocatorImpl.java:1713)
at org.jvnet.hk2.internal.ServiceLocatorImpl.addConfiguration(ServiceLocatorImpl.java:2108)
at org.jvnet.hk2.internal.DynamicConfigurationImpl.commit(DynamicConfigurationImpl.java:262)
at org.glassfish.hk2.utilities.ServiceLocatorUtilities.bind(ServiceLocatorUtilities.java:166)
at org.glassfish.jersey.inject.hk2.AbstractHk2InjectionManager.<init>(AbstractHk2InjectionManager.java:65)
at org.glassfish.jersey.inject.hk2.ImmediateHk2InjectionManager.<init>(ImmediateHk2InjectionManager.java:38)
at org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory$Hk2InjectionManagerStrategy$1.createInjectionManager(Hk2InjectionManagerFactory.java:55)
at org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory.create(Hk2InjectionManagerFactory.java:73)
at org.glassfish.jersey.internal.inject.Injections.createInjectionManager(Injections.java:69)
at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:259)
at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:246)
at org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpContainer.<init>(GrizzlyHttpContainer.java:310)
at org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory.createHttpServer(GrizzlyHttpServerFactory.java:93)
at src.main.java.myApplication.main(myApplication.java:141)
The exception happens in my main-class on creating the http-server:
URI uri= URI.create("http://localhost:8080");
ResourceConfig config = new ResourceConfig();
config.register(myAPI.class);
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(uri, config);
try{
server.start();
} catch( IOException e ) {
logger.error("Exception on starting HTTP-Server.", e);
}
The myAPI.java is nothing special yet and also not important for the problem here, I think. Nevertheless, it looks like this:
public class myAPI extends ResourceConfig{
private static final ObjectMapper mapper = new ObjectMapper();
public myAPI(){
}
#Path("/hello")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response foo() {
ObjectNode json = mapper.createObjectNode();
json.put("status", "ok");
return Response.status(Response.Status.OK).entity(json).build();
}
}
My classpath contains the following huge amount of libraries:
commons-logging-1.1.3.jar
grizzly-framework-3.0.0.jar
grizzly-http-server-3.0.0.jar
grizzly-http-server-multipart-3.0.0.jar
hk2-api-2.6.1.jar
hk2-locator-2.6.1.jar
hk2-utils-2.6.1.jar
jakarta.annotation-api-2.0.0.jar
jakarta.inject-api-2.0.0.jar
jakarta.ws.rs-api-3.0.0.jar
javax.annotation-api-1.3.2.jar
javax.inject-1.jar
jersey-common-3.0.2.jar
jersey-container-grizzly2-http-3.0.2.jar
jersey-guava-2.22.1.jar
jersey-hk2-3.0.2.jar
jersey-server-3.0.2.jar
org.apache.commons.logging-1.1.3.jar
jackson-annotations-2.9.0.jar
jackson-core-2.9.4.jar
jackson-databind-2.9.4.jar
-
httpclient-4.5.13.jar
httpcore-4.4.14.jar
httpmime-4.5.13.jar
log4j-api-2.14.1.jar
log4j-core-2.14.1.jar
The libraries below the dash are needed for another module (http-client) inside my application. I know that I probably could have used some of the libraries there, which I also use for the http-server, but I couldn't get it to work otherwise. But that's not the focus here, only when this is responsible for some kind of collusions due to multiple implementations?! After the long trail-and-error in dependency-hell, it is also possible that some libraries are even not needed.
So the core-question is, how I can put the RequestContext into the singleton-scope?! I haven't even declared a RequestContext anywhere. Do I have to add it in some way?
Side-fact: I also tried the same with the Jersey-JdkHttpServerFactory and ended up with the same error.
I have the following application class which uses a server to run its logic
Implementation of the application class is as follows:
package edu.umd.fcmd.guice.application;
import com.google.inject.Guice;
import com.google.inject.Injector;
public class WebApplication {
private WebServer server;
public void run() {
System.out.println("starting web application...");
Injector injector = Guice.createInjector(new WebGuiceModule());
server = injector.getInstance(WebServer.class);
server.run();
System.out.println("web application finished.");
}
public static void main(String[] args) {
WebApplication app = new WebApplication();
app.run();
}
}
The server class is as follows which depends on three interfaces:
public class WebServer{
private final Frontend frontend;
private final Middleware middleware;
private final Persistance persistance;
#Inject
public WebServer(#Named("front")Frontend frontend, #Named("middle")Middleware middleware, #Named("pers")Persistance persistance) {
this.frontend = frontend;
this.middleware = middleware;
this.persistance = persistance;
}
public String getType() {
return "WebServer";
}
public boolean run() {
System.out.println("running " + this.getType());
Injector injector = Guice.createInjector();
Frontend frontend = injector.getInstance(Frontend.class);
frontend.run();
Middleware middleware = injector.getInstance(Middleware.class);
middleware.run();
Persistance persistance = injector.getInstance(Persistance.class);
persistance.run();
return true;
}
}
My webguicemodule is as follows:
public class WebGuiceModule extends AbstractModule{
#Override
protected void configure(){
bind(WebServer.class).annotatedWith(Names.named("front")).to(FrontEnd.class);
bind(WebServer.class).annotatedWith(Names.named("middle")).to(Middleware.class);
bind(WebServer.class).annotatedWith(Names.named("pers")).to(Persistance.class);
}
}
I am not sure why my module is not working properly. It is still in errors when I am writing the bind statements. Could not figure out why
I am receiving the following errors:
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
The method to(Class<? extends WebServer>) in the type LinkedBindingBuilder<WebServer> is not applicable for the arguments (Class<FrontEnd>)
FrontEnd cannot be resolved to a type
The method to(Class<? extends WebServer>) in the type LinkedBindingBuilder<WebServer> is not applicable for the arguments (Class<Middleware>)
Middleware cannot be resolved to a type
The method to(Class<? extends WebServer>) in the type LinkedBindingBuilder<WebServer> is not applicable for the arguments (Class<Persistance>)
Persistance cannot be resolved to a type
You are not using bind() correctly. You've configured WebGuiceModule such that FrontEnd, Middleware, and Persistance are subclasses of WebServer. However, the compiler errors indicate that is not the case.
You just need to say:
bind(FrontEnd.class);
bind(Middleware.class);
bind(Persistance.class);
Then when you ask the injector for an instance of WebServer, it will know how to create the objects that it needs to pass into the constructor.
WebServer server = injector.getInstance(WebServer.class);
In this case, you don't need #Named. That is for a case like this:
public class Foo {
#Inject
public Foo(#Named("bar") Jar bar, #Named("tar") Jar tar) {
}
}
public interface Jar {}
public class Bar extends Jar {}
public class Tar extends Jar {}
Then in a module...
bind(Jar.class).annotatedWith(Names.named("bar")).to(Bar.class);
bind(Jar.class).annotatedWith(Names.named("tar")).to(Tar.class);
The "name" disambiguates which implementation of Jar to create and inject. Otherwise it wouldn't know, and it would error.
Thank you #JeremyHeiler. This Frontend interface happens to be in a different package. Now, Frontend is dependent on an interface called authentication. When I tried implementing it with the similar code as that of the webserver, I am getting errors. The code I wrote was the following:
package edu.umd.fcmd.guice.interfaces;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import edu.umd.fcmd.guice.application.WebServer;
import edu.umd.fcmd.guice.interfaces.Authentication;
public interface Frontend{
private final Authentication authentication;
#Inject
public interface(Authentication authentication) {
System.out.println("5");
this.authentication = authentication;
}
public static String getType(){
return "Frontend";
}
public default boolean run(){
System.out.println("in frontend");
authentication.run();
return true;
}
}
Errors are the following:
Multiple markers at this line
- Duplicate field Frontend.authentication
- Illegal modifier for the interface field Frontend.authentication; only public, static & final are
permitted
Syntax error on token "interface", Identifier expected
The static field Frontend.authentication should be accessed in a static way
I have tried searching a lot on the internet but could not find figure out. I guess the problem is having files in different packages. If you could please let me know.
Recently I've started developing with Java, and was introduced to the Dropwizard framework. But what's got me stumped here, is that I'm not getting any resources online which would explain how to set it up a Jetty server with my Dropwizard application (I previously made use of Apache Tomcat, but was told that Jetty is a much better alternative). Also, what is use of Embedded-jetty in it?
(I realize that the nature of the question is rather amateurish, but I couldn't come across any online resource that would explain this succinctly :( ...)
The application part:
import io.dropwizard.Application;
public class App extends Application<AppConfiguration> {
public static void main(String[] args) throws Exception {
new App().run(args);
}
#Override
public void run(AppConfiguration configuration, Environment environment) {
final AppResource resource = new AppResource();
environment.jersey().register(resource);
}
The resource with a dummy API to get version:
public class AppResource {
#GET
#UnitOfWork(readOnly = true)
#Path("/version")
#ApiOperation(
value = "Retrieve the version")
#Timed
public Version getVersion() {
return new Version();
}
}
I have a simple Dropwizard 0.8.1 REST service that pulls in Jersey 2.17. Upstream of the REST/Jetty service I have some authentication service that adds some nice authorization information to the HTTP Header that gets passed to my Dropwizard app.
I would love to be able to create a custom annotation in my Resource that hides all the messy header-parsing-to-POJO garbage. Something like this:
#Path("/v1/task")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class TaskResource {
#UserContext // <-- custom/magic annotation
private UserContextData userContextData; // <-- holds all authorization info
#GET
public Collection<Task> fetch() {
// use the userContextData to differentiate what data to return
}
I've spent the last day looking around stackoverflow and found several other people who had the same issue and appeared (?) to get some satisfaction, but I can't seem to avoid getting a "Not inside a request scope" stack trace when I try to do this.
So I stashed all my changes and tried to implement the example provided in sections 22.1 and 22.2 by the Jersey documentation directly: https://jersey.java.net/documentation/2.17/ioc.html
Following along with their example (but in my Dropwizard app), I'm trying to get a "#SessionInject" annotation in my Resource, but it also blows up with "Not inside a request scope" stack trace each time. What am I doing wrong here?
Resource:
#Path("/v1/task")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class TaskResource {
private final TaskDAO taskDAO;
#Context
private HttpServletRequest httpRequest;
#SessionInject
private HttpSession httpSession;
public TaskResource(TaskDAO taskDAO) {
this.taskDAO = taskDAO;
}
#GET
public Collection<Task> fetch(#SessionInject HttpSession httpSession) {
if (httpSession != null) {
logger.info("TOM TOM TOM httpSession isn't null: {}", httpSession);
}
else {
logger.error("TOM TOM TOM httpSession is null");
}
return taskDAO.findAllTasks();
}
The SessionInjectResolver:
package com.foo.admiral.integration.jersey;
import com.foo.admiral.integration.core.SessionInject;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpSession;
import org.glassfish.hk2.api.Injectee;
import org.glassfish.hk2.api.InjectionResolver;
import org.glassfish.hk2.api.ServiceHandle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SessionInjectResolver implements InjectionResolver<SessionInject> {
private static final Logger logger = LoggerFactory.getLogger(HttpSessionFactory.class);
#Inject
#Named(InjectionResolver.SYSTEM_RESOLVER_NAME)
InjectionResolver<Inject> systemInjectionResolver;
#Override
public Object resolve(Injectee injectee, ServiceHandle<?> handle) {
if (HttpSession.class == injectee.getRequiredType()) {
return systemInjectionResolver.resolve(injectee, handle);
}
return null;
}
#Override
public boolean isConstructorParameterIndicator() {
return false;
}
#Override
public boolean isMethodParameterIndicator() {
return false;
}
}
The HttpSessionFactory:
package com.foo.admiral.integration.jersey;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.glassfish.hk2.api.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Singleton
public class HttpSessionFactory implements Factory<HttpSession> {
private static final Logger logger = LoggerFactory.getLogger(HttpSessionFactory.class);
private final HttpServletRequest request;
#Inject
public HttpSessionFactory(HttpServletRequest request) {
logger.info("Creating new HttpSessionFactory with request");
this.request = request;
}
#Override
public HttpSession provide() {
logger.info("Providing a new session if one does not exist");
return request.getSession(true);
}
#Override
public void dispose(HttpSession t) {
}
}
The annotation:
package com.foo.admiral.integration.core;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD})
public #interface SessionInject {
}
And, finally, the binding in the Dropwizard Application class:
#Override
public void run(TodoConfiguration configuration, Environment environment) throws Exception {
...
environment.jersey().register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(HttpSessionFactory.class).to(HttpSession.class);
bind(SessionInjectResolver.class)
.to(new TypeLiteral<InjectionResolver<SessionInject>>() { })
.in(Singleton.class);
}
});
Ye old stack trace:
Caused by: java.lang.IllegalStateException: Not inside a request scope.
at jersey.repackaged.com.google.common.base.Preconditions.checkState(Preconditions.java:149)
at org.glassfish.jersey.process.internal.RequestScope.current(RequestScope.java:233)
at org.glassfish.jersey.process.internal.RequestScope.findOrCreate(RequestScope.java:158)
at org.jvnet.hk2.internal.MethodInterceptorImpl.invoke(MethodInterceptorImpl.java:74)
at org.jvnet.hk2.internal.MethodInterceptorInvocationHandler.invoke(MethodInterceptorInvocationHandler.java:62)
at com.sun.proxy.$Proxy72.getSession(Unknown Source)
at com.foo.admiral.integration.jersey.HttpSessionFactory.provide(HttpSessionFactory.java:29)
at com.foo.admiral.integration.jersey.HttpSessionFactory.provide(HttpSessionFactory.java:14)
Some clues that may be useful:
1) I'm noticing is that the logging statements in my HttpSessionFactory are never getting fired, so I don't think the Factory is correctly identified to DropWizard.
2) If I change the annotation to be a Parameter instead of a Field and move the use of the annotation into the fetch( ) method signature like this, it doesn't throw the stack trace (but the httpSession is still null, presumably because the Factory isn't firing...)
public Collection<Task> fetch(#SessionInject HttpSession httpSession) {
3) It doesn't appear to matter if I "register" the binder with environment.jersey().register() or environment.jersey().getResourceConfig().register()... they appear to do the same thing.
Do you see any obvious problems? Thanks in advance!
This is weird behavior. But what looks like is going on is the following
You have registered TaskResource as an instance and not as a .class. This I'm pretty sure of (though you have not mentioned).
register(new TaskResource());
/* instead of */
register(TaskResource.class);
Doing the former, it set the resource in a singleton scope. The latter in a request scope (unless annotated otherwise - see below)
When the resource model is loading it sees the TaskResource is a singleton, and that the HttpServletRequest is in a request scope. Either that or that the factory is in a per request scope. I'm guessing one of the two.
I thought that it might actually be a scope issue, as mentioned in the error message, but what I'm pretty sure of is that at runtime, it will get handled with a thread local proxy, because of the lesser scope.
You can see it fixed by registering the TaskResource as a class, and then annotating the TaskResource with #Singleton. This is if you actually do want the resource class to be a singleton. If not, then just leave off the #Singleton.
The odd thing to me is that it the fact that it fails on startup when the resource is explicitly instantiated on startup, but works when the framework loads on the first request (which is what happens when you register it as a class). They are both still in a singleton scope.
One thing you might want to take into consideration is whether you actually want the resource to be a singleton or not. You do have to worry about thread safety issues with singletons, and there are are some other limitations. Personally, I prefer to keep them in a request scope. You would have to do some performance testing to see if there is much of an impact for your application.
UPDATE
For parameter injection you may want to take a look at this post
UPDATE 2
See Also
jersey 2 context injection based upon HttpRequest without singleton. My answer should shed some more light.
I meet an odd problem with struts2 annotation, let me elaborate it first
#Results({
#Result(name = "input", location = "main.jsp"),
#Result(name = "list", location = "list.jsp")
})
public class MainAction extends ActionSupport {
private PortalUser user;
#Autowired
private PortalUserService portalUserService;
public String execute() throws Exception {
return INPUT;
}
#Action("addUser")
public String addUser() throws Exception {
portalUserService.addUser(user);
return listUser();
}
#Action("listUser")
#SkipValidation
public String listUser() throws Exception {
List theUserList = portalUserService.getPortalUserList(null);
ServletActionContext.getRequest().setAttribute("userList", theUserList);
return "list";
}
#Action("modifyUser")
public String modifyUser() throws Exception {
List theUserList = portalUserService.getPortalUserList(null);
ServletActionContext.getRequest().setAttribute("userList", theUserList);
return "list";
}
public void validate() {
if (user != null && StringUtils.isBlank(user.getUserName()))
addFieldError("accountBean.userName", "User name is required.");
System.out.println("validate #####");
}
public PortalUser getUser() {
return user;
}
public void setUser(PortalUser user) {
this.user = user;
}
}
this is the struts2 action class, I configure it correctly and type the url
http://domain/listUser it will list all users
http://domain/modifyUser it can modify the users
all things go well in tomcat with exploded class files
But when I build with the war file and deploy it into tomcat webapp folder, the page report
there is no action name listUser.
The difference between the two scenario is exploded class files and archived class files that I compile and jar the action and other class files into it.
I was puzzled about this phenomenon.
So any suggestions and advices will be very appreciated!
I experiment as followings and conclude it that with struts2 annotation,the action class can't move into jar files,it must be located in your WEB-INF/classes
I acknowledge that the struts2 convention will scan action class in the specific package,so I left only the action classes in WEB-INF/classes/.../action folder ,jar other class files and put it into WEB-INF/lib, it's done
By default the plugin does not scan jars or the classpath, solely WEB-INF/classes. You might want to see the plugin's Configuration Reference and look for the value struts.convention.action.includeJars, which lets you list the jars where you also want to look for the files.