001/*
002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Nuxeo - initial API and implementation
018 *
019 * $Id$
020 */
021
022package org.nuxeo.common.xmap;
023
024import java.lang.reflect.InvocationTargetException;
025import java.lang.reflect.Method;
026
027/**
028 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
029 */
030public class XMethodAccessor implements XAccessor {
031
032    private final Method setter;
033
034    private final Class klass;
035
036    Method getter;
037
038    public XMethodAccessor(Method method, Class klass) {
039        setter = method;
040        setter.setAccessible(true);
041        //
042        this.klass = klass;
043    }
044
045    public Class getType() {
046        return setter.getParameterTypes()[0];
047    }
048
049    public void setValue(Object instance, Object value) {
050        try {
051            setter.invoke(instance, value);
052        } catch (IllegalAccessException e) {
053            throw new IllegalArgumentException(e);
054        } catch (InvocationTargetException e) {
055            if (e.getCause() instanceof RuntimeException) {
056                throw (RuntimeException) e.getCause();
057            }
058            throw new IllegalArgumentException(e);
059        }
060    }
061
062    @Override
063    public String toString() {
064        return "XMethodSetter {method: " + setter + '}';
065    }
066
067    public Object getValue(Object instance) {
068        // lazy initialization for getter to keep the compatibility
069        // with current xmap definition
070        if (getter == null) {
071            getter = findGetter(klass);
072        }
073        if (getter != null) {
074            try {
075                return getter.invoke(instance);
076            } catch (IllegalAccessException e) {
077                throw new IllegalArgumentException(e);
078            } catch (InvocationTargetException e) {
079                if (e.getCause() instanceof RuntimeException) {
080                    throw (RuntimeException) e.getCause();
081                }
082                throw new IllegalArgumentException(e);
083            }
084        }
085        return null;
086    }
087
088    private Method findGetter(Class klass) {
089        String setterName = setter.getName();
090        if (setterName.toLowerCase().startsWith("set")) {
091            String suffix = setterName.substring(3);
092            String prefix = null;
093
094            Class<?>[] classes = setter.getParameterTypes();
095            Class<?> clazz = classes[0];
096            // compute the getter name
097            if (clazz == Boolean.class || clazz == Boolean.TYPE) {
098                prefix = "is";
099            } else {
100                prefix = "get";
101            }
102            String getterName = prefix + suffix;
103            try {
104                return klass.getMethod(getterName, new Class[0]);
105            } catch (SecurityException e) {
106                throw new IllegalArgumentException(e);
107            } catch (NoSuchMethodException e) {
108                throw new IllegalArgumentException("there is NO getter defined for annotated setter: " + setterName, e);
109            }
110        }
111        return null;
112    }
113
114}