001    /*******************************************************************************
002     * Portions created by Sebastian Thomschke are copyright (c) 2005-2011 Sebastian
003     * Thomschke.
004     * 
005     * All Rights Reserved. This program and the accompanying materials
006     * are made available under the terms of the Eclipse Public License v1.0
007     * which accompanies this distribution, and is available at
008     * http://www.eclipse.org/legal/epl-v10.html
009     * 
010     * Contributors:
011     *     Sebastian Thomschke - initial implementation.
012     *******************************************************************************/
013    package net.sf.oval.ogn;
014    
015    import java.lang.reflect.AccessibleObject;
016    import java.lang.reflect.Field;
017    import java.lang.reflect.Method;
018    
019    import net.sf.oval.exception.InvalidConfigurationException;
020    import net.sf.oval.internal.util.Assert;
021    import net.sf.oval.internal.util.ReflectionUtils;
022    
023    /**
024     * Default object graph navigator implementation.
025     * 
026     * Object path separator is a colon (.), e.g. owner.address.street
027     * 
028     * The implementation currently is limited to address fields and properties. Separate items of arrays, maps or keys cannot be addressed.
029     * 
030     * @author Sebastian Thomschke
031     */
032    public class ObjectGraphNavigatorDefaultImpl implements ObjectGraphNavigator
033    {
034            public ObjectGraphNavigationResult navigateTo(final Object root, final String path)
035                            throws InvalidConfigurationException
036            {
037                    Assert.argumentNotNull("root", root);
038                    Assert.argumentNotNull("path", path);
039    
040                    Object parent = null;
041                    Object target = root;
042                    AccessibleObject targetAccessor = null;
043                    for (final String chunk : path.split("\\."))
044                    {
045                            parent = target;
046                            if (parent == null) return null;
047                            final Field field = ReflectionUtils.getFieldRecursive(parent.getClass(), chunk);
048                            if (field == null)
049                            {
050                                    final Method getter = ReflectionUtils.getGetterRecursive(parent.getClass(), chunk);
051                                    if (getter == null)
052                                            throw new InvalidConfigurationException("Invalid object navigation path from root object class ["
053                                                            + root.getClass().getName() + "] path: " + path);
054                                    targetAccessor = getter;
055                                    target = ReflectionUtils.invokeMethod(getter, parent);
056                            }
057                            else
058                            {
059                                    targetAccessor = field;
060                                    target = ReflectionUtils.getFieldValue(field, parent);
061                            }
062                    }
063                    return new ObjectGraphNavigationResult(root, path, parent, targetAccessor, target);
064            }
065    }