/*
* ==========================================================================*\
* | $Id: ObjectFieldExtractor.java,v 1.6 2011/06/09 15:44:06 stedwar2 Exp $
* |*-------------------------------------------------------------------------*|
* | Copyright (C) 2007-2010 Virginia Tech | | This file is part of the
* Student-Library. | | The Student-Library is free software; you can
* redistribute it and/or | modify it under the terms of the GNU Lesser General
* Public License as | published by the Free Software Foundation; either version
* 3 of the | License, or (at your option) any later version. | | The
* Student-Library is distributed in the hope that it will be useful, | but
* WITHOUT ANY WARRANTY; without even the implied warranty of | MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the | GNU Lesser General Public
* License for more details. | | You should have received a copy of the GNU
* Lesser General Public License | along with the Student-Library; if not, see
* <http://www.gnu.org/licenses/>.
* \*==========================================================================
*/
package student.web.internal;
import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider;
import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
import com.thoughtworks.xstream.core.JVM;
import java.util.Map;
import java.util.TreeMap;
// -------------------------------------------------------------------------
/**
* Allows an object to be converted to a map of field name/value pairs and vice
* versa. Also provides helper methods for comparing and merging such maps.
*
* @author Stephen Edwards
* @author Last changed by $Author: stedwar2 $
* @version $Revision: 1.6 $, $Date: 2011/06/09 15:44:06 $
*/
public class ObjectFieldExtractor
{
// ~ Instance/static variables .............................................
private transient ReflectionProvider reflectionProvider;
private transient ReflectionProvider pjReflectionProvider = new PureJavaReflectionProvider();
// ~ Constructor ...........................................................
// ----------------------------------------------------------
/**
* Creates a new object.
*/
public ObjectFieldExtractor(ReflectionProvider rp)
{
reflectionProvider = rp;
}
// ~ Public Methods ........................................................
// ----------------------------------------------------------
/**
* Convert an object to a map of field name/value pairs.
*
* @param object
* The object to convert
* @return The object's field values in map form
*/
public Map<String, Object> objectToFieldMap( Object object )
{
final TreeMap<String, Object> result = new TreeMap<String, Object>();
reflectionProvider.visitSerializableFields( object,
new ReflectionProvider.Visitor()
{
@SuppressWarnings("rawtypes")
public void visit(
String fieldName,
Class type,
Class definedIn,
Object value )
{
result.put( fieldName, value );
}
} );
return result;
}
// ----------------------------------------------------------
/**
* Convert an object to a map of field name/value pairs.
*
* @param object
* The object to convert
* @return The object's field values in map form
*/
@SuppressWarnings("unchecked")
public <T> T fieldMapToObject(
Class<T> t, final Map<String, Object> fields)
{
if ( fields == null )
{
return null;
}
Object result = null;
result = reflectionProvider.newInstance( t );
if ( !restoreObjectFromFieldMap( result, fields )
&& !( reflectionProvider instanceof PureJavaReflectionProvider ) )
{
// If some fields weren't initialized, then try to create an
// object using a default constructor, if possible
try
{
Object newResult = pjReflectionProvider.newInstance( t );
restoreObjectFromFieldMap( newResult, fields );
result = newResult;
}
catch ( Exception e )
{
// if we can't create it, there's no default constructor
}
}
return (T)result;
}
private static class BooleanWrapper
{
boolean value;
}
// ----------------------------------------------------------
/**
* Convert an object to a map of field name/value pairs.
*
* @param object
* The object to convert
* @param fields
* The field values to restore from
* @return True if all fields in the object were present in the field set
*/
@SuppressWarnings("unchecked")
public boolean restoreObjectFromFieldMap(
Object object,
final Map<String, Object> fields )
{
final Object result = object;
final BooleanWrapper allFound = new BooleanWrapper();
allFound.value = true;
reflectionProvider.visitSerializableFields( result,
new ReflectionProvider.Visitor()
{
@SuppressWarnings("rawtypes")
public void visit(
String fieldName,
Class type,
Class definedIn,
Object value )
{
if ( fields.containsKey( fieldName ) )
{
reflectionProvider.writeField( result,
fieldName,
fields.get( fieldName ),
definedIn );
}
else
{
allFound.value = false;
}
}
} );
return allFound.value;
}
// ----------------------------------------------------------
/**
* Compute the difference between two field sets. This is not the same as
* "set difference". Instead, it is really the "changes" map minus any
* entries that duplicate those in the "original". In other words, what
* entries in "changes" map to different values than the same entries in
* "original"?
*
* @param original
* The base field set to compare against
* @param changes
* The second (modified) field set
* @return A field set map that contains the values defined in changes that
* are either not present in or are different than in the original.
*/
public Map<String, Object> difference(
Map<String, Object> original,
Map<String, Object> changes )
{
Map<String, Object> differences = new TreeMap<String, Object>();
for ( String key : changes.keySet() )
{
Object value = changes.get( key );
if ( ( value == null && original.get( key ) != null )
|| ( value != null && !value.equals( original.get( key ) ) ) )
{
differences.put( key, value );
}
}
return differences;
}
}