001/*
002 *  Copyright 2013 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.reflection.cloning.implementor;
017
018import java.lang.reflect.Field;
019import java.util.IdentityHashMap;
020
021import org.jadira.reflection.access.model.ClassModel;
022import org.jadira.reflection.access.model.FieldModel;
023import org.jadira.reflection.access.portable.PortableClassAccess;
024import org.jadira.reflection.cloning.api.CloneDriver;
025import org.jadira.reflection.cloning.api.CloneStrategy;
026import org.objenesis.Objenesis;
027import org.objenesis.ObjenesisStd;
028
029/**
030 * A CloneStrategy that uses reflection
031 */
032public class PortableCloneStrategy extends AbstractCloneStrategy implements CloneStrategy {
033
034        private static final char CHAR_NULL = '\u0000';
035
036        private static final Objenesis objenesis = new ObjenesisStd();
037
038        @Override
039        public <T> T newInstance(Class<T> c) {
040                return (T) objenesis.newInstance(c);
041        }
042
043        private static PortableCloneStrategy instance = new PortableCloneStrategy();
044
045        /**
046         * Creates a new instance
047         */
048        public PortableCloneStrategy() {
049        }
050
051    /**
052     * Returns a shared instance of PortableCloneStrategy
053     * @return The instance
054     */
055        public static PortableCloneStrategy getInstance() {
056                return instance;
057        }
058
059        @Override
060        protected <T> void handleTransientField(T copy, FieldModel<T> f) {
061
062                Class<?> clazz = f.getField().getType();
063                try {
064                        if (clazz.isPrimitive()) {
065                                if (java.lang.Boolean.TYPE == clazz) {
066                                        f.getField().setBoolean(copy, false);
067                                } else if (java.lang.Byte.TYPE == clazz) {
068                                        f.getField().setByte(copy, (byte) 0);
069                                } else if (java.lang.Character.TYPE == clazz) {
070                                        f.getField().setChar(copy, CHAR_NULL);
071                                } else if (java.lang.Short.TYPE == clazz) {
072                                        f.getField().setShort(copy, (short) 0);
073                                } else if (java.lang.Integer.TYPE == clazz) {
074                                        f.getField().setInt(copy, 0);
075                                } else if (java.lang.Long.TYPE == clazz) {
076                                        f.getField().setLong(copy, 0L);
077                                } else if (java.lang.Float.TYPE == clazz) {
078                                        f.getField().setFloat(copy, 0.0F);
079                                } else if (java.lang.Double.TYPE == clazz) {
080                                        f.getField().setDouble(copy, 0.0D);
081                                }
082                        } else {
083                                f.getField().set(copy, null);
084                        }
085                } catch (IllegalArgumentException e) {
086                        throw new IllegalStateException("Problem performing clone for field {" + f.getField().getName() + "} of object {" + System.identityHashCode(copy) + "}: " + e.getMessage(), e);
087                } catch (IllegalAccessException e) {
088                        throw new IllegalStateException("Problem performing clone for field {" + f.getField().getName() + "} of object {" + System.identityHashCode(copy) + "}: " + e.getMessage(), e);
089                }
090        }
091
092        @Override
093        protected <W> ClassModel<W> getClassModel(Class<W> clazz) {
094                return PortableClassAccess.get(clazz).getClassModel();
095        }
096
097        @Override
098        protected <T> void handleClonePrimitiveField(T obj, T copy, CloneDriver driver, FieldModel<T> f, IdentityHashMap<Object, Object> referencesToReuse) {
099
100                Field field = f.getField();
101
102                try {
103                        Class<?> clazz = f.getFieldClass();
104
105                        if (java.lang.Boolean.TYPE == clazz) {
106                                field.setBoolean(copy, field.getBoolean(obj));
107                        } else if (java.lang.Byte.TYPE == clazz) {
108                                field.setByte(copy, field.getByte(obj));
109                        } else if (java.lang.Character.TYPE == clazz) {
110                                field.setChar(copy, field.getChar(obj));
111                        } else if (java.lang.Short.TYPE == clazz) {
112                                field.setShort(copy, field.getShort(obj));
113                        } else if (java.lang.Integer.TYPE == clazz) {
114                                field.setInt(copy, field.getInt(obj));
115                        } else if (java.lang.Long.TYPE == clazz) {
116                                field.setLong(copy, field.getLong(obj));
117                        } else if (java.lang.Float.TYPE == clazz) {
118                                field.setFloat(copy, field.getFloat(obj));
119                        } else if (java.lang.Double.TYPE == clazz) {
120                                field.setDouble(copy, field.getDouble(obj));
121                        } else {
122                                throw new IllegalStateException("Expected primitive but was :" + clazz.getName());
123                        }
124
125                } catch (IllegalArgumentException e) {
126                        throw new IllegalStateException("Problem performing clone for field {" + field.getName() + "} of object {" + System.identityHashCode(obj) + "}: " + e.getMessage(), e);
127                } catch (IllegalAccessException e) {
128                        throw new IllegalStateException("Problem performing clone for field {" + field.getName() + "} of object {" + System.identityHashCode(obj) + "}: " + e.getMessage(), e);
129                }
130        }
131
132        @Override
133        protected <T> Object getFieldValue(T obj, FieldModel<T> f) {
134
135                final Field field = f.getField();
136
137                final Object fieldObject;
138
139                try {
140                        fieldObject = field.get(obj);
141
142                } catch (IllegalArgumentException e) {
143                        throw new IllegalStateException("Problem performing clone for field {" + field.getName() + "} of object {" + System.identityHashCode(obj) + "}: " + e.getMessage(), e);
144                } catch (IllegalAccessException e) {
145                        throw new IllegalStateException("Problem performing clone for field {" + field.getName() + "} of object {" + System.identityHashCode(obj) + "}: " + e.getMessage(), e);
146                }
147
148                return fieldObject;
149        }
150
151        @Override
152        protected <T> void putFieldValue(T obj, FieldModel<T> f, Object value) {
153
154                final Field field = f.getField();
155
156                try {
157                        field.set(obj, value);
158
159                } catch (IllegalArgumentException e) {
160                        throw new IllegalStateException("Problem performing clone for field {" + field.getName() + "} of object {" + System.identityHashCode(obj) + "}: " + e.getMessage(), e);
161                } catch (IllegalAccessException e) {
162                        throw new IllegalStateException("Problem performing clone for field {" + field.getName() + "} of object {" + System.identityHashCode(obj) + "}: " + e.getMessage(), e);
163                }
164        }
165}