Struggling with Bean Validation within a JAX RS running in a Glassfish Container - rest

I'm working on a simple Java EE Application, using Glassfish.
Everything runs fine, my Entity and Session Beans are working.
I also created some JAX RS Resources to invoke the Session Beans, which also works fine.
Now I'm struggling with Bean Validation.
Let's have a look at a little snippet:
#GET
#Path( "{portaluser}" )
#NotNull
public PortaluserResponse load( #PathParam( "portaluser" ) #NotBlank #Email final String strEmail )
{ ... some implementation ... }
My Jersey Application, which of course extends ResourceConfig looks like this:
public JerseyApplication()
{
packages( PortaluserService.class.getPackage().getName() );
register( JacksonFeature.class );
register( ValidationConfig.class);
property( ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true );
}
In my pom.xml I included following dependency:
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-bean-validation</artifactId>
<version>2.9</version>
</dependency>
If I invoke the REST Service with nonsense data, the validation doesn't kick in.
Why is that? I expect to get a validation error.
I found a jersey-Sample which covers the bean validation stuff. My REST-Resource works within that project.
The only difference is, that jersey-Sample doesn't run in Glassfish, but in a Jetty.
Can it be that jersey bean validation doesn't work when running in a Java EE container?
Would appreciate some hints.

Related

Is it possible to write JUnit tests that are agnostic to your JAX-RS implementation?

I wrote a REST web service using JAX-RS that knows nothing about the specific JAX-RS implementation I chose. I happen to be using TomEE which means my JAX-RS implementation is ApacheCXF.
I'd like to write unit tests for the web service that also know nothing about the JAX-RS implementation. Is this possible? So far every example I've found involves using classes from a specific JAX-RS implementation (JAXRSClientFactory for ApacheCXF, Jersey Test Framework, etc).
I've started experimenting with tomee-embedded and am able to test my EJB's but it doesn't seem to startup the REST services.
My solution was to use Arquillian paired with an Embedded TomEE. Arquillian provides a ton of functionality but I'm only using it to start/stop the Embedded TomEE. Therefore, all I needed to do was add this to my pom.xml:
<dependency>
<groupId>org.apache.openejb</groupId>
<artifactId>arquillian-tomee-embedded</artifactId>
<version>${tomee.version}</version>
<scope>test</scope>
</dependency>
Then I could write a JUnit test with a little extra Arquillian stuff and plain JAX-RS:
#RunWith(Arquillian.class)
public class MyServiceIT {
#ArquillianResource
private URL webappUrl;
#Deployment()
public static WebArchive createDeployment() {
return ShrinkWrap.create(WebArchive.class)
.addClasses(MyService.class)
.addAsWebInfResource("META-INF/persistence.xml") //Refers to src/main/resources/META-INF/persistence.xml
.addAsWebInfResource("test-resources.xml", "resources.xml") //Refers to src/test/resources/test-resources.xml
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
}
#Test
public void randomTest() throws URISyntaxException {
//Get data from the web service.
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target(webappUrl.toURI().resolve("myentity"));
Response response = webTarget.request(MediaType.APPLICATION_JSON).get();
int status = response.getStatus();
List<MyEntity> myEntities = response.readEntity(new GenericType<List<MyEntity>>() {});
//Perform some tests on the data
}
}

Resteasy Bean Validation Not Working on Remote Server

I have a problem similar to the one described here.
I am using RESTEasy within a standalone Jetty application. When I start the application locally and call a service (e.g. localhost:16880/rest/user/login) bean validation works fine, i.e. I get validation errors like this:
[PARAMETER]
[UserService#login(arg0).appKey]
[app_key may not be null or empty]
[]
However, when I deploy my application to a remote host and call the same service (e.g. remotehost:16880/rest/user/login) bean validation is not invoked at all.
I am using the #ValidateRequest annotation for the service and #Valid annotation for the bean parameter.
My Resteasy version is 3.0.13.Final, though I have tried earlier versions as well. I have tried to write my custom validator, but that didn't work either.
I am puzzled why the validation works locally, but not on remote server. Any suggestions would be highly appreciated.
Since you are using Jetty as standalone server, you have to define RESTEasy validation providers where you define ServletContextHandler. Note that in standalone server there is no container to scan for #Provider classes and to activate them, so you must do it manually.
I expect that you create and start your server app something like:
//create a server listening at some port
Server server= new Server(port);
//add server handlers
HandlerList handlers= new HandlerList();
initHandlers(handlers);
server.setHandler(handlers);
//start the server
server.start();
In initHandlers you must have defined your RESTEasy support:
public void initHandlers(List<HandlerList> handlers) {
//define root context handler
ServletContextHandler servletContextHandler= new ServletContextHandler(ServletContextHandler.SESSIONS);
servletContextHandler.setContextPath("/");
handlers.addHandler(servletContextHandler);
//define RESTEasy handler
ServletHolder restServlet= new ServletHolder(new HttpServlet30Dispatcher());
//since this is a standalone server, somewhere you have to define RESTful services and Singletons
restServlet.setInitParameter("javax.ws.rs.Application", "com.exampleapp.MyRestApplication");
restServlet.setInitParameter("resteasy.servlet.mapping.prefix", "rest");
servletContextHandler.addServlet(restServlet, "rest/*");
}
So what is left to do now is to add Validation provider as init parameter:
restServlet.setInitParameter("resteasy.providers", "org.jboss.resteasy.plugins.validation.ValidatorContextResolver,org.jboss.resteasy.api.validation.ResteasyViolationExceptionMapper");
On this link I tried to find the name of the validator providers: https://docs.jboss.org/resteasy/docs/3.0.4.Final/userguide/html/Validation.html
RESTEasy obtains a bean validation implemenation by looking in the available META-INF/services/javax.ws.rs.Providers files for an implementation of ContextResolver
So it does not say what, but says where. Now open the "resteasy-hibernatevalidator-provider-3...*.jar (from Eclipse -> Maven dependencies or manually unzip) and look into META-INF/services/javax.ws.rs.ext.Providers It says:
org.jboss.resteasy.plugins.validation.hibernate.ValidatorContextResolver
org.jboss.resteasy.api.validation.ResteasyViolationExceptionMapper
If you don't have this dependency, then add it to your pom file:
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-hibernatevalidator-provider</artifactId>
<version>${resteasy.version}</version>
</dependency>
One more note: that at the same place where you described validation providers, you also add other providers, if you happen to need them (such as JacksonJaxbJson, etc).

java ee lookup ejbs from from different app

Java EE Tutorial is not helpful at all. Internet search was underwhelming.
I have an EJB module that is deployed to glassfish by itself. It has #Local and #Remote annotated iterfaces which are both implemented by the concrete class.
Then i have a REST resource that needs to get a reference to that ejb module and invoke some methods.
Can you give me a barebones, simple example of how that is done? I mean, i can't even inject SessionContext into my rest app, as it crashes... Please, keep it simple.
The ejb should just have a:
public String getMsg(){
return "ohai";
}
The rest service:
#GET
#Produces("text/plain")
public String asd(){
return <the myterious ejb that was injected somehow>.getMsg();
}
Thanks.
Alright, i figured it out. Using NetBeans, but probably applicable to Eclipse. Server - glassfish
Create webapp, an EJB -> call EJB from webapp. All these run inside the same server as separate modules.
First: create an EJB module, it will be deployed on its own:
remote interface:
package main;
import javax.ejb.Remote;
#Remote
public interface YourRemoteInterface{
public String tellMeSomething();
public void otherMethod(); //etc...
}
then create the EJB implementation class:
concrete implementation
package main;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.ejb.EJB; //crucial to JNDI lookup
#Remote(RemoteInterface.class)
#Stateless
#EJB(name="java:global:/MYSTUFF", beanInterface=YourRemoteInterface.class)
public class YourConcreteClass implements YourRemoteInterface{
#Override
public String tellMeSomething(){//...} //and do the other methods
}
#EJB name attribute names your bean, that you will use to look it up. Can by any name. For ex: "some-name", or "java:global/YourConcreteClass"
Part two - webapp:
For web app i used a rest service, but surely can be another EJB or a SE client app. For SE client you'd need to set connection info, but that for another life.
#Path("/somePath")
public class Service{
#GET
#Produces("text/plain")
public String qwe(){
try{
javax.naming.InitialCOntext ic = new javax.naming.InitialContext();
YourRemoteInterface rb = (YourRemoteInterface)ic.lookup("java:global:/MYSTUFF");
return rb.tellMeSomething();
} catch (Exception ex) {
return "F*uck your life";
}
}
}
Now, from Project Properties of your webapp, you need to:
1) add the ejb jar file to Libraries so it shows in the Compile tab. I used the "Add project" button
2) Build -> Packaging: add the ejb jar file to WAR content. I used "Add file/folder", where i navigated to NetBeans projects / the EJB module / build / dist
note: you may experience an error when trying to deploy the ejb, or redeploy it. Error name is: java.lang.RuntimeException: Error while binding JNDI name main.RemoteInterface#main.RemoteInterface for EJB RemoteBean . Skipping the vague explanation, to cure it, you need to execute a command in glassfish:
asadmin set server.ejb-container.property.disable-nonportable-jndi-names="true"
Now, you can compile the webapp and deploy it. Should work.
At the end it's that simple. I swear i've eaten the WHOLE ejb section in glassfish tutorial and nowhere do they tell you this stuff. It's so annoying.

JAX-RS service as #Stateless EJB : NameNotFoundException

I try to build a Java EE 7 app with Rest services and EJB injection.
I created a multi module maven project which I deploy on Glassfish 4. My final EAR contain a JAR with my EJBs, with for example my Rest services definitions :
#Stateless
#Path("countries")
public class CountryRest {
//#EJB
//StockService stockService;
#GET
public Response getCountries() {
//stockService.getAll(); --> firing a NPE, stockService is Null
return Response.ok().build();
}
}
#Stateless
#Remote(IStockService.class)
public class StockService implements IStockService {
#Override
public List<Stock> getAllStock() {
return new ArrayList<Stock>();
}
}
When I deploy my app, I see the following logs which seems ok. Even if I wonder why it defines "java:global" JNDI since by default #Stateless EJB is #Local :
Portable JNDI names for EJB CountryRest: [java:global/GeoData-ear/GeoData-ejb-1.0-SNAPSHOT/CountryRest, java:global/GeoData-ear/GeoData-ejb-1.0-SNAPSHOT/CountryRest!com.tomahim.geodata.rest.CountryRest]
Portable JNDI names for EJB StockService: [java:global/GeoData-ear/GeoData-ejb-1.0-SNAPSHOT/StockService, java:global/GeoData-ear/GeoData-ejb-1.0-SNAPSHOT/StockService!com.tomahim.geodata.services.IStockService]
Then when I'm doing a GET on /rest/countries, the status is 200 as expected but I have a NameNotFoundException / NamingException :
Avertissement: An instance of EJB class, com.tomahim.geodata.rest.CountryRest, could not be looked up using simple form name. Attempting to look up using the fully-qualified form name.
javax.naming.NamingException: Lookup failed for 'java:module/CountryRest' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NameNotFoundException: No object bound to name java:module/CountryRest]
I see that the lookup for "java:module/ContryRest" is not matching "java:global/.../CountryRest" but what am I doing wrong ?
EDIT 1 : I was able to make #Ejb injection work by placing my Rest definitions ans EJBs in my webapp maven module deploy as a WAR. So it seems that the problem occur only when I deploy my EJB in a JAR. Any idea ? What could be the difference between JAR and WAR deployment ?
It is required by the JAX-RS spec that all REST endpoints must live within your WAR file. Do you really need an EAR file?

Restlet - Connection Problems - 406 Not Acceptable - Plain Text

couldnt find somewhere else advice.
I am writing a Restlet JSE Client for a Jersey(!) Restful Service. I already wrote a Jersey client for that and it is working, so the jersey service is alright. Now I get problems in writing a restlet client:
My Service root adress is:
http://localhost:8080/com-project-core/rest, so I call:
ClientResource = service = new ClientResource("http://localhost:8080/com-project-core/rest");
My Basic Auth Credentiels are admin and xxx, so I call:
service.setChallengeResponse(ChallengeScheme.HTTP_BASIC, "admin", "xxx");
Now the problems:
ClientResource service = new ClientResource("http://localhost:8080/com-project-core/rest/ping");
calls up my service. After that I try
String myString = service.get(String.class);
System.out.println(myString);
I get a:
08.07.2012 17:41:48 org.restlet.engine.http.connector.HttpClientHelper start
INFO: Starting the default HTTP client
in my output. Not more! The Junit Test says:
Not Acceptable (406) - Not Acceptable
So he can find the resource but cannot produce #Produces("text/plain") ??
So when I remove #Produces("text/plain") on server side it works!!
For the resourcey my server side looks like this:
#Path("/ping")
#RolesAllowed({"admin", "user"})
public class ConnectedResourceBean implements ConnectedResourceIF {
#GET
#Produces("text/plain")
public String getPingMessage() throws NamingException {
return "Hello World";
}
}
For my pom in set this dependencies:
<dependency>
<groupId>org.restlet.jse</groupId>
<artifactId>org.restlet</artifactId>
<version>${restlet.version}</version>
</dependency>
<dependency>
<groupId>org.restlet.jse</groupId>
<artifactId>org.restlet.ext.xstream</artifactId>
<version>${restlet.version}</version>
</dependency>
As I said, its working with my jersey client.
No way: Restlet had problems with
#Produces("text/plain")
on jersey server side. Can someone explain me that fact?
Edit:
Made it work with
<properties>
<restlet.version>2.1-M3</restlet.version>
</properties>