org.apache.wicket.injection.Injector Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of wicket-ioc Show documentation
Show all versions of wicket-ioc Show documentation
Wicket IoC common dependencies for injection and proxying. Used by
Spring, Guice, etc.
/*
* 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.wicket.injection;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import org.apache.wicket.Application;
import org.apache.wicket.MetaDataKey;
import org.apache.wicket.util.collections.ClassMetaCache;
/**
* Injector scans fields of an object instance and checks if the specified
* {@link IFieldValueFactory} can provide a value for a field; if it can, the field is set to that
* value. Injector will ignore all non-null fields.
*
* @author Igor Vaynberg (ivaynberg)
*
*/
public abstract class Injector
{
private static final MetaDataKey KEY = new MetaDataKey()
{
private static final long serialVersionUID = 1L;
};
private final ClassMetaCache cache = new ClassMetaCache();
/**
* Binds current instance of the injector to the Application. After this method is called this
* instance of injector will be returned from subsequent calls to {@link #get()} whenever the
* specified application object is active in the thread.
*
* @param application
*/
public void bind(final Application application)
{
application.setMetaData(KEY, this);
}
/**
* @return Injector associated with the application instance
*/
public static Injector get()
{
return Application.get().getMetaData(KEY);
}
/**
* Injects the specified object. This method is usually implemented by delegating to
* {@link #inject(Object, IFieldValueFactory)} with some {@link IFieldValueFactory}
*
* @param object
*
* @see #inject(Object, IFieldValueFactory)
*/
public abstract void inject(Object object);
/**
* traverse fields in the class hierarchy of the object and set their value with a locator
* provided by the locator factory.
*
* @param object
* @param factory
*/
protected void inject(final Object object, final IFieldValueFactory factory)
{
final Class> clazz = object.getClass();
Field[] fields = null;
// try cache
fields = cache.get(clazz);
if (fields == null)
{
// cache miss, discover fields
fields = findFields(clazz, factory);
// write to cache
cache.put(clazz, fields);
}
for (final Field field : fields)
{
if (!field.isAccessible())
{
field.setAccessible(true);
}
try
{
if (field.get(object) == null)
{
Object value = factory.getFieldValue(field, object);
if (value != null)
{
field.set(object, value);
}
}
}
catch (IllegalArgumentException e)
{
throw new RuntimeException("error while injecting object [" + object.toString() +
"] of type [" + object.getClass().getName() + "]", e);
}
catch (IllegalAccessException e)
{
throw new RuntimeException("error while injecting object [" + object.toString() +
"] of type [" + object.getClass().getName() + "]", e);
}
}
}
/**
* Returns an array of fields that can be injected using the given field value factory
*
* @param clazz
* @param factory
* @return an array of fields that can be injected using the given field value factory
*/
private Field[] findFields(Class> clazz, final IFieldValueFactory factory)
{
List matched = new ArrayList();
while (clazz != null)
{
Field[] fields = clazz.getDeclaredFields();
for (final Field field : fields)
{
if (factory.supportsField(field))
{
matched.add(field);
}
}
clazz = clazz.getSuperclass();
}
return matched.toArray(new Field[matched.size()]);
}
}