Not long ago, I created an article on how to execute Web API (Hatena Bookmark Entry Information Acquisition API) using Retrofit + Gson.
I got the source code of Retrofit from github and investigated the implementation method that enables Web API access processing just by creating an interface.
As a result, I found that I am using Proxy of reflection API.
Since the processing is verbose / poor visibility, there may not be many cases where Proxy is used in the implementation of the application, but I thought it was an interesting usage.
Retrofit is an Android (Java) app, an open source library for easy Web API (json data) access. Use in combination with json data conversion library (gson, jackson, etc.).
Web API execution process is implemented by the following procedure.
First, implement the interface for API. The following interface is an example of Hatena Bookmark Entry Information Acquisition API.
// HatenaApiInterface.java
public interface HatenaApiInterface {
String END_POINT = "http://b.hatena.ne.jp";
String TARGET_URL = "http://b.hatena.ne.jp/ctop/it";
//Hatena Bookmark Entry Information Acquisition API
// http://developer.hatena.ne.jp/ja/documents/bookmark/apis/getinfo
@GET("/entry/jsonlite/")
Call<BookmarkEntry> getBookmarkEntry(@Query("url") String target);
}
The following URL is the URL of the Hatena Bookmark Entry Information Acquisition API (GET) related to technology. Where url is a category argument. Please refer to here for the specifications of Hatena Bookmark Entry Information Acquisition API.
http://b.hatena.ne.jp/entry/jsonlite/?url=http%3A%2F%2Fb.hatena.ne.jp%2Fctop%2Fit
Describe the information that can generate this URL in the interface.
The endpoint is the root URL of the Web API. Used when creating an instance of Retrofit.
The method name is arbitrary.
The annotation (@GET) indicates that you are using the GET method and that the relative path of the Web API is `/ entry / jsonlite /`
. Also, the annotation (@Query) is added as a query string under?
Follow the steps below to access the Web API. (Main) Implement in Activity etc.
//Retrofit instance creation
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(HatenaApiInterface.END_POINT)
.addConverterFactory(GsonConverterFactory.create())
.build();
//Creating an interface for Web API access
mApiInterface = retrofit.create(HatenaApiInterface.class);
//Web API execution instance(interface)To get.
Call<BookmarkEntry> call = mApiInterface.getBookmarkEntry(targetUrl);
//Run the web API
//The processing result is notified by the callback call
call.enqueue(new Callback<BookmarkEntry>() {
@Override
public void onResponse(Call<BookmarkEntry> call, Response<BookmarkEntry> response) {
//Describes the process when Web API access is successful
}
@Override
public void onFailure(Call<BookmarkEntry> call, Throwable t) {
//Describes the process when Web API access fails
}
});
Below is the source for Retrofit.create.
InvocationHandler is created and returned using Proxy of reflection API. When you execute getBookmarkEntry of the acquired interface (instance), the invoke method is executed. The method name getBookmarkEntry is stored in the argument Method, and the String targetUrl is stored in the argument args.
Get the Web API access information associated with this method with loadServiceMethod. Add another okHttp call class and return the Adapter class. Set this to a variable of type Call <BookmarkEntry> call
Then execute the enqueque method to make a Web API call. The result can be obtained by calling back the argument.
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
Explains how to use Proxy of reflection API. Seeing is believing. Create TestInterface and TestProxy and try running TestProxy. You can see the above explanation well.
For how to use Proxy, I referred to here.
$ java TestProxy
$ cat TestInterface.java
public interface TestInterface {
public void doSomething();
}
$ cat TestProxy.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class TestProxy {
private Object proxy;
private TestProxy(Class<TestInterface> clazz) {
this.proxy = Proxy.newProxyInstance(clazz.getClassLoader(),
new Class[] { clazz },
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//Output method information
System.out.println("method: " + method);
return null;
}
});
}
public static TestInterface createProxy(Class<TestInterface> clazz) {
TestProxy obj = new TestProxy(clazz);
return clazz.cast(obj.proxy);
}
public static void main(String[] args) {
TestInterface someInterface = TestProxy.createProxy(TestInterface.class);
someInterface.doSomething();
}
}
Recommended Posts