JAX-RS を使うと REST クライアントが簡単に書けることを知ったが、
一つ問題があった。
具体的には、以下のようなことがやりたかった。
@Path("/json_sample")
public abstract class SampleRESTServer {
/**
* このメソッドではサーバーにデータを取得して POJO で返す
*/
@GET
@Path("/hello.js")
public abstract Message getMessageJSON();
/**
* このメソッドは、POJOの一部だけ返す
*/
public String getMessage() {
return this.getMessageJSON().getMessage();
}
}
REST でデータを取得する部分だけは JAX-RS の実装に任せて、ついでにその実装に依存した abstract なメソッドはそのまま動かして欲しい。
が、そんな実装は無かった。需要高いと思うんだけどな……
仕方ないので org.apache.cxf.common.util.CglibProxyHelper を Monkey Patch してみました。
↓のファイルを字面通りのパスに java ファイルとして配置して、クラスを上書きしてやるだけです。
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cxf.common.util;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
class CglibProxyHelper extends ProxyHelper {
@Override
protected Object getProxyInternal(ClassLoader loader, Class<?>[] interfaces,
final java.lang.reflect.InvocationHandler h) {
Class<?> superClass = null;
List<Class<?>> theInterfaces = new ArrayList<Class<?>>();
for (Class<?> c : interfaces) {
if (!c.isInterface()) {
if (superClass != null) {
throw new IllegalArgumentException("Only a single superclass is supported");
}
superClass = c;
} else {
theInterfaces.add(c);
}
}
if (superClass != null) {
Enhancer enhancer = new Enhancer();
enhancer.setClassLoader(loader);
enhancer.setSuperclass(superClass);
enhancer.setInterfaces(theInterfaces.toArray(new Class[theInterfaces.size()]));
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
throws Throwable {
return h.invoke(obj, method, args);
}
});
return enhancer.create();
} else {
return super.getProxyInternal(loader, interfaces, h);
}
}
}
今のところうまく動いています。