I'm trying to test my code which uses the new Java 11 java.net.http.HttpClient.
In my production code I have something like this:
HttpClient httpClient = ... (gets injected)
HttpRequest request = HttpRequest.newBuilder().uri(URI.create("http://localhost:1234"))
.POST(HttpRequest.BodyPublishers.ofByteArray("example".getBytes()))
.build();
return httpClient.send(request, HttpResponse.BodyHandlers.ofByteArray());
And in my test I mock the HttpClient and so get the java.net.http.HttpRequest. How do I get/test its request body (= my "example")? I can call request.bodyPublisher() to get a HttpRequest.BodyPublisher, but then I'm stuck.
I've tried to cast it to jdk.internal.net.http.RequestPublishers.ByteArrayPublisher (which it actually is), but it won't compile because the corresponding package is not exported by the module.
I've checked the available methods in the HttpRequest.BodyPublisher-interface (.contentLength(), .subscribe(subscriber)) but I guess it's not possible with them.
I've tried to just create a new BodyPublisher and compare them using .equals(), but there is no real implementation of it and so the comparison was always false.
If you are interested in how body will look like in handler you can know it with help of HttpRequest.BodyPublisher Subscriber. We call subscription.request in order to receive all body items and collect them.
Our custrom subscriber:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Flow;
public class FlowSubscriber<T> implements Flow.Subscriber<T> {
private final CountDownLatch latch = new CountDownLatch(1);
private List<T> bodyItems = new ArrayList<>();
public List<T> getBodyItems() {
try {
this.latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return bodyItems;
}
#Override
public void onSubscribe(Flow.Subscription subscription) {
//Retrieve all parts
subscription.request(Long.MAX_VALUE);
}
#Override
public void onNext(T item) {
this.bodyItems.add(item);
}
#Override
public void onError(Throwable throwable) {
this.latch.countDown();
}
#Override
public void onComplete() {
this.latch.countDown();
}
}
Usage in the test:
#Test
public void test() {
byte[] expected = "example".getBytes();
HttpRequest.BodyPublisher bodyPublisher =
HttpRequest.BodyPublishers.ofByteArray(expected);
FlowSubscriber<ByteBuffer> flowSubscriber = new FlowSubscriber<>();
bodyPublisher.subscribe(flowSubscriber);
byte[] actual = flowSubscriber.getBodyItems().get(0).array();
Assert.assertArrayEquals(expected, actual);
}
Related
This post relates to this get exchange from within pojo without changing it's interface
and the solution to this problem was to use MDC.
here is the code to do so: (taken from camel test code)
given this interface for instance
public interface IEcho {
String echo(String param);
}
and configuration like so :
import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
import org.junit.Test;
import org.slf4j.MDC;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import static org.junit.Assert.assertEquals;
public class RetrieveCorrelationIdTest {
#Test
public void testCamel() throws Exception {
DefaultCamelContext ctx = new DefaultCamelContext();
try {
ctx.setUseMDCLogging(true);
ctx.addRoutes(createRouteBuilder());
ctx.start();
Object body = ctx.createProducerTemplate().requestBody("direct:a", "text in body");
assertEquals("TEXT IN BODY", body);
} finally {
ctx.stop();
}
}
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
IEcho proxy = (IEcho) ReflectHelper.simpleProxy(IEcho.class, new Proxybean(getContext()));
from("direct:a").routeId("route-a")
.setHeader("CUSTOM-CORRELATION-ID", constant("correlationIdsetInHeader"))
.process(exchange -> MDC.put("CUSTOM-HEADER-MDC", "correlationIdsetWithMDC"))
.bean(proxy, "echo(${body})");
from("direct:b").routeId("route-b")
.process(exchange -> {
String customHeader = (String) exchange.getIn().getHeader("CUSTOM-CORRELATION-ID");
String mdcHeader = MDC.get("CUSTOM-HEADER-MDC");
assertEquals(customHeader, mdcHeader);
exchange.getIn().setBody(((String)exchange.getIn().getBody()).toUpperCase());
})
.to("mock:result");
}
};
}
class Proxybean implements InvocationHandler {
CamelContext ctx;
Proxybean(CamelContext ctx) {
this.ctx = ctx;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("echo")) {
// how to get the CUSTOM-CORRELATION-ID here ????µ
// only possible with MDC ?
String mdcHeader = MDC.get("CUSTOME-HEADER-MDC");
String result =
(String) ctx.createProducerTemplate()
.requestBodyAndHeader("direct:b", args[0], "CUSTOME-HEADER", mdcHeader);
return result;
}
return null;
}
}
}
see comments in code:
// how to get the CUSTOM-CORRELATION-ID here ????µ
// only possible with MDC ?
I can access some data even without the exchange using MDC
so my questions:
if I want to get a correlationId spanning from an endpoint calling beans method that calls other method exposed through a proxy that uses a producerTemplate to make the call etc etc...
Is that possible without MDC, does camel offers another way to retrieve this information?
I'm trying to build a library that basically wraps our api. Basically, the structure im going for is something like this:
MySDK mySDK = new MySDK("username", "password");
mySDK.getPlaylistInfo("3423", 2323, new CustomCallback<>(){
//on response
//on failure
});
So with vanilla Retrofit, an api call usually looks something like the following:
ApiService api = retrofit.create(ApiService.class);
Call<Response> call = api.getPlaylistInfo()
call.enqueue(new Callback<Response>() {
#Override
public void onResponse(Call<Response> call, Response<Response> response) {
//handle response
}
#Override
public void onFailure(Call<Response> call, Throwable t) {
//handle failure
}
});
Basically, how would I wrap retrofits callback system into my own? Note, the reason for needing to do this is to preprocess the data returned from the api before delivering the final response.
I've written something similar so it might help you getting started, this follows an implementation I'v written for Volley, and re-used when I migrated to Retrofit2 so it resembles it (this SO question).
Create a global object (what you would refer to as MySDK) as a singelton class that handles your requests:
create a singleton class, which you instatiate when you're application comes up:
public class NetworkManager
{
private static final String TAG = "NetworkManager";
private static NetworkManager instance = null;
private static final String prefixURL = "http://some/url/prefix/";
//for Retrofit API
private Retrofit retrofit;
private ServicesApi serviceCaller;
private NetworkManager(Context context)
{
retrofit = new Retrofit.Builder().baseUrl(prefixURL).build();
serviceCaller = retrofit.create(ServicesApi.class);
//other stuf if you need
}
public static synchronized NetworkManager getInstance(Context context)
{
if (null == instance)
instance = new NetworkManager(context);
return instance;
}
//this is so you don't need to pass context each time
public static synchronized NetworkManager getInstance()
{
if (null == instance)
{
throw new IllegalStateException(NetworkManager.class.getSimpleName() +
" is not initialized, call getInstance(...) first");
}
return instance;
}
public void somePostRequestReturningString(Object param1, final SomeCustomListener<String> listener)
{
String url = prefixURL + "this/request/suffix";
Map<String, Object> jsonParams = new HashMap<>();
jsonParams.put("param1", param1);
Call<ResponseBody> response;
RequestBody body;
body = RequestBody.create(okhttp3.MediaType.parse(JSON_UTF), (new JSONObject(jsonParams)).toString());
response = serviceCaller.thePostMethodYouWant("someUrlSufix", body);
response.enqueue(new Callback<ResponseBody>()
{
#Override
public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> rawResponse)
{
try
{
String response = rawResponse.body().string();
// do what you want with it and based on that...
//return it to who called this method
listener.getResult("someResultString");
}
catch (Exception e)
{
e.printStackTrace();
listener.getResult("Error1...");
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable throwable)
{
try
{
// do something else in case of an error
listener.getResult("Error2...");
}
catch (Exception e)
{
throwable.printStackTrace();
listener.getResult("Error3...");
}
}
});
}
public void someGetRequestReturningString(Object param1, final SomeCustomListener<String> listener)
{
// you need it all to be strings, lets say id is an int and name is a string
Call<ResponseBody> response = serviceCaller.theGetMethodYouWant
(String.valueOf(param1.getUserId()), param1.getUserName());
response.enqueue(new Callback<ResponseBody>()
{
#Override
public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> rawResponse)
{
try
{
String response = rawResponse.body().string();
// do what you want with it and based on that...
//return it to who called this method
listener.getResult("someResultString");
}
catch (Exception e)
{
e.printStackTrace();
listener.getResult("Error1...");
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable throwable)
{
try
{
// do something else in case of an error
listener.getResult("Error2...");
}
catch (Exception e)
{
throwable.printStackTrace();
listener.getResult("Error3...");
}
}
});
}
}
This works with your interface (example with POST and GET request, GET could be without params):
public interface BelongServicesApi
{
#POST("rest/of/suffix/{lastpart}") // with dynamic suffix example
Call<ResponseBody> thePostMethodYouWant(#Path("lastpart") String suffix, #Body RequestBody params);
#GET("rest/of/suffix") // with a fixed suffix example
Call<ResponseBody> theGetMethodYouWant(#Query("userid") String userid, #Query("username") String username);
}
when your application comes up:
public class MyApplication extends Application
{
//...
#Override
public void onCreate()
{
super.onCreate();
NetworkManager.getInstance(this);
}
//...
}
a simple listener interface for your callback (seperate file would do good):
public interface SomeCustomListener<T>
{
public void getResult(T object);
}
and finally, from wherever you want, the context is already in there, just call:
public class BlaBla
{
//.....
public void someMethod()
{
//use the POST or GET
NetworkManager.getInstance().somePostRequestReturningString(someObject, new SomeCustomListener<String>()
{
#Override
public void getResult(String result)
{
if (!result.isEmpty())
{
//do what you need with the result...
}
}
});
}
}
you can use any object with the listener, just parse the response string to a corresponding object, depending on what you need to receive and you can call that from everywhere (onClicks, etc.), just remember the objects need to match between methods.
Hope this Helps!
I'm new to retrofit and i am trying te get a json response to an object called RootObject. The error that i am stuck with is :
"Error:(21, 44) error: incompatible types: NewsController cannot be
converted to Callback>"
Does someone now my mistake here? thanks in regards!
public class NewsController {
public void getNews(){
Retrofit retrofit = new Retrofit.Builder().baseUrl("apilink").addConverterFactory(GsonConverterFactory.create()).build();
GetNewsService service = retrofit.create(GetNewsService.class);
try {
service.GetNewsItems().enqueue(this); //asynchronous
Response<List<RootObject>> response = service.GetNewsItems().execute(); //synchronous
}
catch (IOException e){
}
}
}
class to put the data:
public class RootObject implements Serializable {
public ArrayList<Result> results ;
public int nextId;
public ArrayList<Result> getResults() { return results; }
public int getNextId() { return nextId; }
public String toString() {
return String.format("JEEJ" + nextId);
}
}
Interface:
public interface GetNewsService {
#GET("/Articles")
Call<List<RootObject>> GetNewsItems();
}
First of all,
change your interface to this:
public interface GetNewsService {
#GET("/Articles")
void GetNewsItems(Callback<List<RootObject>> cb);
}
Also change your newsController class.
public class NewsController {
private RestAdapter restAdapter;
static final String API_URL = "[Enter your API base url here]";
public void getNews(){
OkHttpClient mOkHttpClient = new OkHttpClient();
mOkHttpClient.setConnectTimeout(15000,TimeUnit.MILLISECONDS);
mOkHttpClient.setReadTimeout(15000,TimeUnit.MILLISECONDS);
restAdapter = new RestAdapter.Builder().setEndpoint(API_URL).setClient(new OkClient(mOkHttpClient)).setLogLevel(RestAdapter.LogLevel.FULL) .build();
GetNewsService service = restAdapter.create(GetNewsService.class);
Callback<List<RootObject> cb = new Callback<List<RootObject>>() {
#Override
public void success(List<RootObject> rootObjectList, Response response) {
//whatever you want to do with the fetched news items
}
#Override
public void failure(RetrofitError error) {
//whatever you want to do with the error
}
};
service.GetNewsItems(cb);
}
}
You'll need to add the following dependencies in your build.gradle:
compile 'com.squareup.retrofit:retrofit:1.9.0'
compile 'com.google.code.gson:gson:2.3.1'
compile 'com.squareup.okhttp:okhttp:2.4.0'
#megh vidani's answer works, but he had you switch your code from Retrofit 2 to Retrofit 1. Here is how to do it in Retrofit 2. You would need to go back to your original gradle settings, etc. --
public class NewsController {
public void getNews(){
Retrofit retrofit = new Retrofit.Builder().baseUrl("apilink").addConverterFactory(GsonConverterFactory.create()).build();
GetNewsService service = retrofit.create(GetNewsService.class);
service.GetNewsItems().enqueue(new Callback<List<RootObject>>() {
#Override
public void onResponse(Response<List<RootObject>> response) {
// Handle your response
// Note HTTP errors are delivered here, you can check
// response.isSuccess() or response.code() to determine
// HTTP failures
}
#Override
public void onFailure(Throwable t) {
// Network errors
}
});
}
}
new to Java programming, I am just trying to understand how I can make this class be tested. I have made a Queue class:
public class Queue<E> {
private ArrayList<E> items;
public Queue(){
items = new ArrayList<E>();
}
public void join(E e) {
items.add(e);
}
public E leave() throws EmptyQueueError {
if (items.isEmpty()) {
throw new EmptyQueueError();
}
return items.remove(0);
}
}
I want to make a JUnit called QueueTest that is automatically reset to empty before each test that is commenced? Then I want it check that removing an item from an empty queue throws an EmptyQueueError? Finally, I want it to check that when several items join an (initially) empty queue, it is the first item that joined which is the first to leave?
It's a tutorial I am following but it fails to make me understand. I have made the class above and I have attempted the JTest class:
package queue;
public class QueueTest<e> {
private Queue q;
#Before
public void setUp() throws Exception {
}
#After
public void tearDown() throws Exception {
}
#Test
public void test() {
q = new Queue<e>();
assertEquals("Empty Queue", 0, q);
}
}
Am I close to what I am trying to achieve? I am trying to do the first one.
Thank you for your help and ample time.
You're doing well.
#Test
public void test() {
q = new Queue<e>();
assertEquals("Empty Queue", 0, q);
}
The problem with this is that you make a new Queue instance, but you don't do anything with it.
Then your test's innards could be
#Test
public void test() {
Queue<Integer> q = new Queue<Integer>(); // A
try {
Integer ignore = q.leave(); // B
fail("exception expected"); // C
} catch (EmptyQueueError ex) {
// implicit success // D
}
}
What this means is that you'd make a Queue ('A'), then immediately try to get an item ('B'). This should cause an exception. If it does not, your test fails with "exception expected" ('C'). If the expected exception is thrown, you code works ('D')
I'll post more once you get this working.
Try this: they run for me. You aren't far off.
package cruft;
import java.util.ArrayList;
public class Queue<E> {
private ArrayList<E> items;
public Queue(){
items = new ArrayList<E>();
}
public void join(E e) {
items.add(e);
}
public E leave() throws EmptyQueueError {
if (items.isEmpty()) {
throw new EmptyQueueError();
}
return items.remove(0);
}
// Note: I added this.
public int size() { return this.items.size(); }
}
}
And here's the test:
package cruft;
import org.junit.Assert;
import org.junit.Test;
public class QueueTest {
#Test
public void test() {
Queue<String> q = new Queue<String>();
Assert.assertEquals("queue should be empty", 0, q.size());
}
}
Notice: You should just create an instance in the test. Make sure your queue has a concrete type of thing to hold (String in this case).
Remember what generics are doing for you: they let you create a collection or container whose behavior doesn't depend on the type of objects it holds onto. So you might have a Queue that contains Strings or Persons or Penguins.
So what are you trying to test here? When you do assertEquals("Empty Queue", 0, q) what are you attempting to test here? That the Queue is empty?
For the asserts what they usually take is something to test, IE Q == 0, and they take an optional message, which will be printed out if the test fails.
The flaw in why your assertEquals fails is something that you can see by investigating what the value of q is.
Here is how to do it with TestNG, showing how to test an exception and how to reset the queue before each test method:
public class QueueTest {
private Queue q = new Queue();
#BeforeMethod
public void setUp() throws Exception {
q.reset();
}
#Test(expectedExceptions = EmptyQueueError.class)
public void shouldThrowIfRemovingFromEmpty() {
assertTrue(q.isEmpty());
q.remove(0);
}
}
If you want to be very strict, you should probably test that each queue is initially empty and the exception in two separate test methods.
I'm looking for a way to extract the essence of a signature in Java. The reason is that I want to use the signature as a unique key in a Map for my java.lang.reflect.Proxies.
With this code:
public interface MyInterface {
public int compute(String s);
}
...
public static void main (String... args) throws Exception {
InvocationHandler handler = ...;
MyInterface i = (MyInterface) Proxy.newProxyInstance(
Beans.class.getClassLoader(),
new Class<?>[] { MyInterface.class },
handler);
Method m1 = MyInterface.class.getMethod("compute", String.class);
Method m2 = i.getClass().getMethod("compute", String.class);
System.out.printf("%b%f", m1.equals(m2));
}
The result is obviously false.
This code is not the code I'll use, because I need it inside the InvocationHandler, but I'm wondering if regarding the Proxy implementations and the interface, getting method.getName() and method.getParameterTypes() is enough or I should use method.getTypeParameters() and method.getParameterAnnotations() as well?
In short: how to get a method signature that is the same for an interface and its java.lang.reflect.Proxy implementations?
I think you want the Method passed in the InvocationHandler.
package playtest;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import static junit.framework.Assert.*;
interface MyInterface {
void run();
void about();
void run(String j);
}
public class TestProxyClass {
#Test
public void testDeclaringClass() throws Exception {
final Map<Method, Runnable> actions = new HashMap<Method, Runnable>();
actions.put(MyInterface.class.getMethod("run"), new Runnable() {
#Override
public void run() {
System.out.println("run");
}
} );
actions.put(MyInterface.class.getMethod("run", String.class), new Runnable() {
#Override
public void run() {
System.out.println("run string");
}
} );
actions.put(MyInterface.class.getMethod("about"), new Runnable() {
#Override
public void run() {
System.out.println("about");
}
} );
MyInterface face = (MyInterface) Proxy.newProxyInstance(getClass().getClassLoader(),
new Class<?>[] { MyInterface.class }, new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
actions.get(method).run();
return null;
}
} );
face.run();
face.about();
face.run("Hello");
}
}
What about using the result of Method.toGenericString as the key? The string it returns includes all details of the signature, as far as I can tell.
Another thing that might be useful is: Method m2 = i.getClass().getMethod("compute", String.class).getDeclaringClass().getMethod("compute", String.class);. That might result in m1.equals(m2) returning true.
I just had a bug with code doing this, I took name, genericReturnType and genericParameterTypes, and I had problems when working with proxies because I lost the generic information.
I switched to use name, returnType and parameterTypes and it works fine...
I also considered using declaringClass but I removed it and don't remember exactly how I did this...