JAX-RS/RestEasy Client and JSON-P - jax-rs

In a REST client written using JAX-RS and RestEasy as implementation I'm trying the send a JsonObject via POST to a WebService. The project uses the reference implementation of JSON-P, org.glassfish.javax.json.
When I'm trying the send the request I get the following exception:
javax.ws.rs.ProcessingException: RESTEASY003215: could not find writer for content-type application/json type: org.glassfish.json.JsonObjectBuilderImpl$JsonObjectImpl
The following artifacts are present in the pom.xml:
<dependency>
<groupId>javax.json</groupId>
<artifactId>javax.json-api</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>3.6.3.SP1</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>3.6.3.SP1</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-json-p-provider</artifactId>
<version>3.6.3.SP1</version>
</dependency>
From what I've read in the documentation that should be all necessary.
The request in invoked as follows:
final JsonObjectBuilder credentialsBuilder = Json.createObjectBuilder();
credentialsBuilder.add("username", configuration.getServiceUser());
credentialsBuilder.add("password", configuration.getServicePassword());
final Entity<JsonObject> credentials = Entity
.json(credentialsBuilder.build());
final Response response = ClientBuilder
.newClient()
.target("http://www.example.org/some/url")
.request(MediaType.APPLICATION_JSON)
.post(credentials);
What I'm missing?

It seems like your provider is not being registered; depending on how/where you're using Resteasy, you might need to do additional configuration to make sure it picks up that kind of stuff for you (http://docs.jboss.org/resteasy/docs/3.6.3.Final/userguide/html_single).
For example, if you're using servlet configuration, you might need to use resteasy-servlet-initializer, or add in a spring helper, etc.
Note that you can most likely explicitly register the JSON-P provider to the Client, Target, or Request itself when you're building it out if you wanted to (or are just testing)

Thanks for the hint. That was indeed the solution. The application is a command line client (Java SE). The solution was - in addition to add the dependencies - to do register the providers when creating the client instance:
ClientBuilder
.newClient()
.register(JsonArrayProvider.class)
.register(JsonObjectProvider.class)
.register(JsonStructureProvider.class)
.register(JsonValueProvider.class)
... // create request

Related

Will Roku WebDriver setup work with my Java framework

I know Roku Webdriver repository comes with python and Postman sample scripts but I was wondering if I could use my Java scripts - not javascript - to connect to go and automate. If so, does anyone have any examples how to setup the driver in Java?
https://developer.roku.com/en-ca/docs/developer-program/dev-tools/automated-channel-testing/web-driver.md
You can give a try Rokuality.
From README: it is one of the first projects to provide support for the Roku WebDriver API.
If it is not up-to-date, you can take a core as a basis for your test framework
My recommendation would be to download the solution that Roku provides, read the API documentation, use their sample solution for Python, JavaScript and/or Postman to get familiar with the technology, then write your own solution for Java.
The core of the Roku WebDriver solution is an HTTP server which sends ECP commands (remote control primarily) and is able to query the XML source of the Roku channel under test to responses in JSON wire protocol format. Using the documentation and the sample libraries, it will be a straight forward task to write a class for your Java solution which can send GET and POST requests to the WebDriver HTTP server. You can use the Roku provided Go language solution to compile binaries for the HTTP server on the platform(s) you want to support (Mac/Linux/Windows, etc.) and then include the binaries in your solution. You will also want to write a class to to launch and manage the state of the HTTP server and likely extend the solution further to do other things like parsing the responses of the JSON responses from the server, capturing logs from devices and saving screenshots.
Though I have not used Java with Roku WebDriver, I started working with Roku WebDriver shortly after it was released. We wanted to use JavaScript and at the time, Roku had not yet released their JavaScript library, so I wrote one for the project I am working on. It was a pretty straight forward task with Roku's API documentation and Robot Framework library to reference. I see no reason you couldn't do the same in Java, C# or comparable languages.
Note: another user pointed out the Rokuality solution. While it certainly wouldn't hurt to review their implementation to learn from it, it would seem to have a lot of complexity which you don't likely need. A lot of the solution seems designed to interact with the Rokuality cloud service offering and at this point their domain doesn't go anywhere, so I'm not sure they are still up and running.
I figured it out. If anyone is interested in automating it in Java, this code will work as a starting point. Make sure to connect to Go server first. The steps are on https://developer.roku.com/en-ca/docs/developer-program/dev-tools/automated-channel-testing/automated-testing-overview.md . Dont forget to update bash or zshrc with
export GOPATH=/Users/$USER/eclipse-workspace/automated-channel-testing-master
Once the server is running, run the code. Make sure you add your own IP. Thats located in settings on the Roku device. Also add a close method so that you wont get any errors that the "session is already running". If you do get that, just reset the server.
Again this is just a starting point - use the APIs in https://developer.roku.com/en-ca/docs/developer-program/dev-tools/automated-channel-testing/web-driver.md to really start automating.
String ip ;
JSONObject json;
String cookie;
public RokuDriver(String IP) {
this.ip = IP;
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
RequestBody body = RequestBody.create("{\n\t\"ip\": \""+ip+"\"\n}", MediaType.parse("application/json"));
Request request = new Request.Builder()
.url("http://localhost:9000/v1/session")
.method("POST", body)
.addHeader("Content-Type", "application/json")
.build();
try {
Response response = client.newCall(request).execute();
JSONObject jsonBody = new
JSONObject(response.body().string());
cookie = jsonBody.getString("sessionId");
System.out.println(jsonBody.toString(4));
response.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
close();
}
}
public void down() {
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create("{\n\t\"button\": \"down\"\n}", MediaType.parse("application/json"));
Request request = new Request.Builder()
.url("http://localhost:9000/v1/session/"+cookie+"/press")
.method("POST", body)
.addHeader("Content-Type", "application/json")
.build();
try {
Response response = client.newCall(request).execute();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
POM:
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.8.1</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp-urlconnection</artifactId>
<version>4.8.1</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20200518</version>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>

WebClient max header size

Is there any way I can configure the max header size for a response?
I get the following error from the netty framework :
io.netty.handler.codec.TooLongFrameException: HTTP header is larger than 8192 bytes.
at io.netty.handler.codec.http.HttpObjectDecoder$HeaderParser.newException(HttpObjectDecoder.java:983)
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Apparently reactor added an API for this, but I don't see how is this controllable in the WebClient of spring Web Flux. I am using the following version
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>2.3.2.RELEASE</version>
</dependency>
Any ideas?
You can configure reactor's reactor.netty.http.client.HttpClient to have custom maxHeaderSize and plug this preconfigured HttpClient in your WebClient instance.
HttpClient httpClient =
HttpClient.create().httpResponseDecoder(spec -> spec.maxHeaderSize(32 * 1024));
WebClient webClient =
WebClient.builder().clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
In a Spring Boot app, the max HTTP header size is configured using:
server.max-http-header-size=65536
I have found this solved the above issue on spring cloud gateway, so worth a try.

How to Configure CAS v4.2.7 to enable X.509 Authentication

What I have done
First, I cloned the repository of the CAS project from github and switched to the tag v4.2.7.
git clone https://github.com/apereo/cas.git
git checkout v4.2.7
Then I build using gradlew tool
./gradlew
Finally, I copied the artifact ./cas-server-webapp/build/libs/cas-server-webapp-4.2.7.war, and extract it to run, it just works well.
But since I want to configure the CAS using the X.509 Authentication method, the result is frustrated, because the login web flow XML file is different: all of solutions to using a X.509 Authentication method say first to substitute the generateLoginTicket with startAuthenticate like this: https://wiki.jasig.org/display/CASUM/X.509+Certificates, but the "generateLoginTicket" is gone in the file /WEB-INF/webflow/login/login.xml of the version 4.2.7. And the documentation of the CAS is also of no help, https://apereo.github.io/cas/4.2.x/installation/X509-Authentication.html
I want to study how to configure the CAS v4.2.7 using a X.509 Authentication method. I would be appreciate if you could help me out.
As per my personal experience with 5.0 version overlay add to pom.xml
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-x509-webflow</artifactId>
<version>${cas.version}</version>
</dependency>
And add proper CA certificates to the server keystore.

Can Spring Cloud Sleuth trace HTTP calls made through Async RestTemplate

I am trying to trace HTTP calls made through Async RestTemplate from a Spring Boot Application.
I have a ZipKin instance running locally to which the microservices in question point to.
I could see spans recorded at every service in ZipKin UI, however I am not able to see the trace covering all the spans.
With RestTemplate the trace is recorded as normal. i.e. I am able to see end-to-end via the UI.
Any pointers will help,
Thanks in advance.
I'm not sure this is what you are expecting, you can add this dependancy in pom.xml if you are using maven:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
and a AlwaysSampler #Bean in your SpringBootApplication class
#Bean
public AlwaysSampler defaultSampler(){
return new AlwaysSampler();
}
This will help you to sample your inputs in zipkin all time.

Customizing JSON marhsalling with GlassFish v4

We've got a JAX-RS application that runs on Apache TomEE. We slightly customize the default Jettison provider to better adhere to JSON conventions used by JavaScript frontend. TomEE allows to do it via its resources.xml file:
<resources>
<Service id="jettison" class-name="org.apache.cxf.jaxrs.provider.json.JSONProvider">
serializeAsArray = true
dropRootElement = false
arrayKeys = members,roles
supportUnwrapped = true
writeXsiType = false
</Service>
</resources>
Now we are migrating to GlassFish v4.1, and we notice that JSON output differs from what we had in TomEE - thus completely breaking frontend. I'm looking for similar mechanism to customize JSON marshaller in GlassFish. In fact, I'm already a little bit stuck with Jersey, MOXy, Jackson, Jettison. How do we know which JSON provider is actually used? How do we select one? How do we customize the behavior?
The application is pure JAX-RS and does not use any JSON processor directly, instead relying on marshalling of JAXB-annotated classes. Introduction of any non-JavaEE dependencies is highly undesirable, since the application is intended to be portable across containers (TomEE, GlassFish, some day WildFly). Config-file method, similar to TomEE, is preferable; programmatic way is acceptable, too - but only if portability is maintained.
Glassfish uses MOXy as the default provider. Internally it has the libraries to handle Jackson, Jettison, and MOXy, but the default is MOXy. There are two ways to disable MOXy
Set the Jersey property jersey.config.server.disableMoxyJson to true.
Register a different XxxJsonFeature that disables MOXy. For instance the JacksonFeature that comes with jersey-media-json-jackson
Note that Glassfish comes with a Jackson provider, but it is Jackson 1.x. If you want to use 2.x, instead of the using the jersey-media-json-jackson dependency listed above, it would be better to use the underlying Jackson provider dependency, which is
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.6.0</version>
</dependency>
You can register the JacksonJsonProvider or the JacksonJaxbJsonProvider for JAXB annotation support.
To configure Jackson, the easiest way to implement a ContextResolver, as seen in this answer. The JacksonJsonProvider will lookup this ContextResolver to retrieve the ObjectMapper used for (de)serialization.
You will also need to remember to disable MOXy, as mentioned above.
Also one thing to note is that this solution is portable. With JAX-RS, the only portable application configuration is through an Application subclass
#ApplicationPath("/api")
public class MyApplication extends Application {}
That being said, the disabling of MOXy in the case of Glassfish, is nothing more than setting a property. In the Application class, you can override getProperties() which returns a Map<String, Object>. This is where you can set the property. And because it s nothing more than a String (no outside dependencies), it remains portable
#ApplicationPath("/api")
public class MyApplication extends Application {
#Override
public Map<String, Object> getProperties() {
Map<String, Object> props = new HashMap<>();
props.put("jersey.config.server.disableMoxyJson", true);
return props;
}
}
As far as the above Jackson dependency, it is also a portable solution. It it nothing (JAX-RS) implementation specific. It implements and uses standard JAX-RS APIs