001/*
002 * Copyright 2013 Chris Pheby
003 * Licensed under the Apache License, Version 2.0 (the "License");
004 * you may not use this file except in compliance with the License.
005 * You may obtain a copy of the License at
006 * http://www.apache.org/licenses/LICENSE-2.0
007 * Unless required by applicable law or agreed to in writing, software
008 * distributed under the License is distributed on an "AS IS" BASIS,
009 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
010 * See the License for the specific language governing permissions and
011 * limitations under the License.
012 */
013package org.jadira.reflection.cloning.orika;
014
015import java.util.HashSet;
016import java.util.Set;
017
018import ma.glasnost.orika.CustomConverter;
019import ma.glasnost.orika.MappingContext;
020import ma.glasnost.orika.metadata.Type;
021import ma.glasnost.orika.metadata.TypeFactory;
022
023import org.jadira.reflection.cloning.BasicCloner;
024import org.jadira.reflection.cloning.api.CloneStrategy;
025import org.jadira.reflection.cloning.api.Cloner;
026
027/**
028 * This class is intended for use with Orika
029 * <br>
030 * ClonerConverter allows configuration of a number of specific types which should be copied
031 * using BasicCloner.
032 * <br>
033 * This allows you to declare your own set of types which should be copied instead of mapped.
034 * You can use this type with Orika independently of the rest of the cloning framework to perform
035 * fast deep clones within Orika.
036 */
037public class ClonerConverter extends CustomConverter<Object, Object> {
038
039    private Cloner cloner;
040    
041    private Set<Type<?>> types = new HashSet<Type<?>>();
042
043    /**
044     * Constructs a new ClonerConverter configured to handle the provided list of types by
045     * cloning.
046     * @param types one or more types that should be copied using the ClonerConverter
047     */
048    public ClonerConverter(java.lang.reflect.Type... types) {
049
050        this(new BasicCloner(), types);
051    }
052
053    /**
054     * Constructs a new ClonerConverter configured to handle the provided list of types by
055     * cloning.
056     * @param cloneStrategy Strategy to be used
057     * @param types one or more types that should be copied using the ClonerConverter
058     */
059    public ClonerConverter(CloneStrategy cloneStrategy, java.lang.reflect.Type... types) {
060
061        this.cloner = new BasicCloner(cloneStrategy);
062
063        if (types.length == 0) {
064            this.types = null;
065        }
066        for (java.lang.reflect.Type type : types) {
067            this.types.add(TypeFactory.valueOf(type));
068        }
069    }
070
071    
072    /**
073     * Constructs a new ClonerConverter configured to handle the provided list of types by
074     * cloning.
075     * @param cloner Cloner implementation to be used
076     * @param types one or more types that should be copied using the ClonerConverter
077     */
078    public ClonerConverter(Cloner cloner, java.lang.reflect.Type... types) {
079
080        this.cloner = cloner;
081
082        if (types.length == 0) {
083            this.types = null;
084        }
085        for (java.lang.reflect.Type type : types) {
086            this.types.add(TypeFactory.valueOf(type));
087        }
088    }
089
090    private boolean shouldCopy(Type<?> type) {
091        
092        if (types == null) {
093            return true;
094        }
095        
096        for (Type<?> registeredType : types) {
097            if (registeredType.isAssignableFrom(type)) {
098                return true;
099            }
100        }
101        return false;
102    }
103
104    @Override
105    public boolean canConvert(Type<?> sourceType, Type<?> destinationType) {
106        return shouldCopy(sourceType) && sourceType.equals(destinationType);
107    }
108
109    @Override
110    public Object convert(Object source, Type<? extends Object> destinationType, MappingContext context) {
111
112        if (source == null) {
113            return null;
114        }
115        return cloner.clone(source);
116    }
117}