001/*
002 *  Copyright 2010, 2011 Chris Pheby
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 */
016package org.jadira.bindings.core.general.unmarshaller;
017
018import java.lang.reflect.Constructor;
019import java.lang.reflect.InvocationTargetException;
020import java.lang.reflect.Modifier;
021
022import org.jadira.bindings.core.api.BindingException;
023import org.jadira.bindings.core.api.FromUnmarshaller;
024
025/**
026 * Unmarshaller supports constructor parameterised by a target object
027 * @param <S> Source type for the conversion
028 * @param <T> Target type
029 */
030public final class ConstructorFromUnmarshaller<S, T> implements FromUnmarshaller<S, T> {
031
032    private final Constructor<S> unmarshal;
033
034    private final Class<S> boundClass;
035    
036    private final Class<T> targetClass;
037    
038    /**
039     * Create a new instance
040     * @param unmarshal Constructor to be used
041     */
042    public ConstructorFromUnmarshaller(Constructor<S> unmarshal) {
043        
044        this.boundClass = unmarshal.getDeclaringClass();
045        
046        if (getBoundClass().isInterface() 
047                || Modifier.isAbstract(getBoundClass().getModifiers()) 
048                || getBoundClass().isLocalClass() 
049                || getBoundClass().isMemberClass()) {
050            throw new IllegalStateException("unmarshal constructor must have an instantiable target class");
051        }
052        
053        if (unmarshal.getParameterTypes().length != 1) {
054                throw new IllegalStateException("unmarshal constructor must have a single parameter");
055        }
056        
057        this.unmarshal = unmarshal;
058        
059        @SuppressWarnings("unchecked")
060        Class<T> myTarget = (Class<T>)unmarshal.getParameterTypes()[0];
061        this.targetClass = myTarget;
062    }
063
064        /**
065         * {@inheritDoc}
066         */
067        /* @Override */
068    public S unmarshal(T object) {
069        
070        if (object != null && !targetClass.isAssignableFrom(object.getClass())) {
071                throw new IllegalArgumentException("Supplied object was not instance of target class");
072        }
073        
074        try {
075            return unmarshal.newInstance(object);
076        } catch (IllegalAccessException ex) {
077            throw new IllegalStateException("Constructor is not accessible");
078        } catch (InstantiationException ex) {
079            throw new IllegalStateException("Constructor is not valid");
080        } catch (InvocationTargetException ex) {
081            if (ex.getCause() instanceof RuntimeException) {
082                throw (RuntimeException) ex.getCause();
083            }
084            throw new BindingException(ex.getMessage(), ex.getCause());
085        }
086    }
087    
088        /**
089         * {@inheritDoc}
090         */
091        /* @Override */
092    public Class<S> getBoundClass() {
093        return boundClass;
094    }
095    
096        /**
097         * {@inheritDoc}
098         */
099        /* @Override */
100    public Class<T> getTargetClass() {
101        return targetClass;
102    }
103}