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.binding;
017
018import java.lang.reflect.Constructor;
019import java.lang.reflect.InvocationTargetException;
020import java.lang.reflect.Method;
021import java.lang.reflect.Modifier;
022
023import org.jadira.bindings.core.api.Binding;
024import org.jadira.bindings.core.api.BindingException;
025import org.jadira.bindings.core.general.marshaller.MethodToMarshaller;
026
027/**
028 * Binding that supports a to contract, and a constructor parameterised by a S
029 * @param <S> Source type for the conversion
030 * @param <T> Target type
031 */
032public final class MethodConstructorBinding<S, T> extends MethodToMarshaller<S, T> implements Binding<S, T> {
033
034    private final Constructor<S> unmarshal;
035
036    /**
037     * Constructs a binding that supports a marshal method and an unmarshalling constructor
038     * @param unmarshal The Constructor
039     * @param targetClass The target class for marshalling to
040     * @param marshal The marshalling method
041     */
042    public MethodConstructorBinding(Constructor<S> unmarshal, Class<T> targetClass, Method marshal) {
043        
044        super(unmarshal.getDeclaringClass(), targetClass, marshal);
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        this.unmarshal = unmarshal;
054    }
055
056    /**
057     * {@inheritDoc}
058     */
059    @Override
060    public S unmarshal(T str) {
061        try {
062            return unmarshal.newInstance(str);
063        } catch (IllegalAccessException ex) {
064            throw new IllegalStateException("Constructor is not accessible");
065        } catch (InstantiationException ex) {
066            throw new IllegalStateException("Constructor is not valid");
067        } catch (InvocationTargetException ex) {
068            if (ex.getCause() instanceof RuntimeException) {
069                throw (RuntimeException) ex.getCause();
070            }
071            throw new BindingException(ex.getMessage(), ex.getCause());
072        }
073    }
074}