Wicket 1.5 RC4.2 が出ているので、wicket-guice を確かめた。まだ JSR-330 に未対応であった。
guice 3.0 に合わせた JSR-330対応は簡単な修正だと思うのだが。。。
http://blog.zaq.ne.jp/oboe2uran/article/507/
で示した CustomGuiceFieldValueFactory は、以下のとおり
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import org.apache.wicket.Application;
import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.guice.GuiceInjectorHolder;
import org.apache.wicket.injection.IFieldValueFactory;
import org.apache.wicket.proxy.IProxyTargetLocator;
import org.apache.wicket.proxy.LazyInitProxyFactory;
import org.apache.wicket.util.lang.WicketObjects;
import com.google.inject.BindingAnnotation;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
/**
* CustomGuiceFieldValueFactory. for JSR-330 and guice-Inject
*/
class CustomGuiceFieldValueFactory implements IFieldValueFactory,Serializable{
private final boolean wrapInProxies;
CustomGuiceFieldValueFactory(final boolean wrapInProxies){
this.wrapInProxies = wrapInProxies;
}
@Override
public Object getFieldValue(final Field field, final Object fieldOwner){
Object target = null;
if (supportsField(field)){
if (!Modifier.isStatic(field.getModifiers())){
com.google.inject.Inject injectAnnotation = field.getAnnotation(com.google.inject.Inject.class);
if (injectAnnotation != null){
try{
Annotation bindingAnnotation = findBindingAnnotation(field.getAnnotations());
final IProxyTargetLocator locator
= new GuiceProxyTargetLocator(field,bindingAnnotation,injectAnnotation.optional());
if (this.wrapInProxies){
target = LazyInitProxyFactory.createProxy(field.getType(), locator);
}else{
target = locator.locateProxyTarget();
}
if (!field.isAccessible()){
field.setAccessible(true);
}
field.set(fieldOwner, target);
}catch(IllegalAccessException e){
throw new WicketRuntimeException("Error Guice-injecting field "+field.getName()+" in "+fieldOwner, e);
}catch (MoreThanOneBindingException e){
throw new RuntimeException("Can't have more than one BindingAnnotation on field "
+field.getName()+" of class "+fieldOwner.getClass().getName());
}
}else{
javax.inject.Inject injectJsr330 = field.getAnnotation(javax.inject.Inject.class);
if (injectJsr330 != null){
try{
Annotation bindingAnnotation = findBindingAnnotation(field.getAnnotations());
final IProxyTargetLocator locator = new GuiceProxyTargetLocator(field,bindingAnnotation,false);
if (this.wrapInProxies){
target = LazyInitProxyFactory.createProxy(field.getType(), locator);
}else{
target = locator.locateProxyTarget();
}
if (!field.isAccessible()){
field.setAccessible(true);
}
field.set(fieldOwner, target);
}catch(IllegalAccessException e){
throw new WicketRuntimeException("Error Guice-injecting field "+field.getName()+" in "+fieldOwner, e);
}catch (MoreThanOneBindingException e){
throw new RuntimeException("Can't have more than one BindingAnnotation on field "
+field.getName()+" of class "+fieldOwner.getClass().getName());
}
}
}
}
}
return target;
}
@Override
public boolean supportsField(final Field field){
return field.isAnnotationPresent(com.google.inject.Inject.class) || field.isAnnotationPresent(javax.inject.Inject.class);
}
private Annotation findBindingAnnotation(final Annotation[] annotations) throws MoreThanOneBindingException{
Annotation bindingAnnotation = null;
// Work out if we have a BindingAnnotation on this parameter.
for (Annotation annotation : annotations){
if (annotation.annotationType().getAnnotation(BindingAnnotation.class) != null){
if (bindingAnnotation != null){
throw new MoreThanOneBindingException();
}
bindingAnnotation = annotation;
}else if(annotation.annotationType().equals(javax.inject.Named.class)){
bindingAnnotation = annotation;
}
}
return bindingAnnotation;
}
public class MoreThanOneBindingException extends Exception{
private static final long serialVersionUID = 1L;
}
class GuiceProxyTargetLocator implements IProxyTargetLocator{
private static final long serialVersionUID = 1L;
private final Annotation bindingAnnotation;
private final boolean optional;
private final String className;
private final String fieldName;
public GuiceProxyTargetLocator(final Field field, final Annotation bindingAnnotation,final boolean optional){
this.bindingAnnotation = bindingAnnotation;
this.optional = optional;
this.className = field.getDeclaringClass().getName();
this.fieldName = field.getName();
}
@Override
public Object locateProxyTarget(){
final GuiceInjectorHolder holder = Application.get().getMetaData(GuiceInjectorHolder.INJECTOR_KEY);
final Type type;
try{
Class<?> clazz = WicketObjects.resolveClass(this.className);
final Field field = clazz.getDeclaredField(this.fieldName);
type = field.getGenericType();
}catch(Exception e){
throw new WicketRuntimeException("Error accessing member: "+this.fieldName+" of class: "+this.className, e);
}
// using TypeLiteral to retrieve the key gives us automatic support for
// Providers and other injectable TypeLiterals
final Key<?> key;
if (this.bindingAnnotation==null){
key = Key.get(TypeLiteral.get(type));
}else{
key = Key.get(TypeLiteral.get(type), this.bindingAnnotation);
}
Injector injector = holder.getInjector();
// if the Inject annotation is marked optional and no binding is found
// then skip this injection (WICKET-2241)
if (this.optional){
// Guice 2.0 throws a ConfigurationException if no binding is find while 1.0 simply
// returns null.
try{
if (injector.getBinding(key)==null){
return null;
}
}catch(RuntimeException e){
return null;
}
}
return injector.getInstance(key);
}
}
}
---------------------------------------------
import org.apache.wicket.Application;
import org.apache.wicket.Component;
import org.apache.wicket.application.IComponentInstantiationListener;
import org.apache.wicket.guice.GuiceInjectorHolder;
import org.apache.wicket.injection.IFieldValueFactory;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Stage;
/**
* CustomGuiceComponentInjector. for JSR-330 and guice-Inject
*/
public class CustomGuiceComponentInjector extends org.apache.wicket.injection.Injector
implements IComponentInstantiationListener{
private final IFieldValueFactory fieldValueFactory;
public CustomGuiceComponentInjector(final Application app){
this(app, new Module[0]);
}
public CustomGuiceComponentInjector(final Application app,final Module... modules){
this(app, Guice.createInjector(app.usesDeploymentConfig()
? Stage.PRODUCTION : Stage.DEVELOPMENT, modules), true);
}
public CustomGuiceComponentInjector(final Application app,final Injector injector){
this(app, injector, true);
}
public CustomGuiceComponentInjector(final Application app,final Injector injector
,final boolean wrapInProxies){
app.setMetaData(GuiceInjectorHolder.INJECTOR_KEY, new GuiceInjectorHolder(injector));
this.fieldValueFactory = new CustomGuiceFieldValueFactory(wrapInProxies);
bind(app);
}
@Override
public void inject(final Object object){
inject(object,this.fieldValueFactory);
}
@Override
public void onInstantiation(final Component component){
inject(component);
}
}