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.api.ClassAccess;
022import org.jadira.reflection.access.asm.AsmClassAccess;
023import org.jadira.reflection.access.model.ClassModel;
024import org.jadira.reflection.access.model.FieldModel;
025import org.jadira.reflection.cloning.api.CloneDriver;
026import org.jadira.reflection.cloning.api.CloneStrategy;
027
028/**
029 * A CloneStrategy that uses ASM
030 */
031public class AsmCloneStrategy extends AbstractCloneStrategy implements CloneStrategy {
032
033        private static final char CHAR_NULL = '\u0000';
034
035        @Override
036        public <T> T newInstance(Class<T> c) {
037
038                ClassAccess<T> classAccess = AsmClassAccess.get(c);
039                return classAccess.newInstance();
040        }
041
042        private static AsmCloneStrategy instance = new AsmCloneStrategy();
043
044    /**
045     * Returns a shared instance of AsmCloneStrategy
046     * @return The instance
047     */
048        public static AsmCloneStrategy getInstance() {
049                return instance;
050        }
051
052        @Override
053        protected <T> void handleTransientField(T copy, FieldModel<T> f) {
054
055                Class<?> clazz = f.getField().getType();
056                try {
057                        if (f.isPrivate()) {
058                                if (clazz.isPrimitive()) {
059                                        if (java.lang.Boolean.TYPE == clazz) {
060                                                f.getField().setBoolean(copy, false);
061                                        } else if (java.lang.Byte.TYPE == clazz) {
062                                                f.getField().setByte(copy, (byte) 0);
063                                        } else if (java.lang.Character.TYPE == clazz) {
064                                                f.getField().setChar(copy, CHAR_NULL);
065                                        } else if (java.lang.Short.TYPE == clazz) {
066                                                f.getField().setShort(copy, (short) 0);
067                                        } else if (java.lang.Integer.TYPE == clazz) {
068                                                f.getField().setInt(copy, 0);
069                                        } else if (java.lang.Long.TYPE == clazz) {
070                                                f.getField().setLong(copy, 0L);
071                                        } else if (java.lang.Float.TYPE == clazz) {
072                                                f.getField().setFloat(copy, 0.0F);
073                                        } else if (java.lang.Double.TYPE == clazz) {
074                                                f.getField().setDouble(copy, 0.0D);
075                                        }
076                                } else {
077                                        f.getField().set(copy, null);
078                                }
079                        } else {
080                                if (clazz.isPrimitive()) {
081                                        if (java.lang.Boolean.TYPE == clazz) {
082                                                f.getFieldAccess().putBooleanValue(copy, false);
083                                        } else if (java.lang.Byte.TYPE == clazz) {
084                                                f.getFieldAccess().putByteValue(copy, (byte) 0);
085                                        } else if (java.lang.Character.TYPE == clazz) {
086                                                f.getFieldAccess().putCharValue(copy, CHAR_NULL);
087                                        } else if (java.lang.Short.TYPE == clazz) {
088                                                f.getFieldAccess().putShortValue(copy, (short) 0);
089                                        } else if (java.lang.Integer.TYPE == clazz) {
090                                                f.getFieldAccess().putIntValue(copy, 0);
091                                        } else if (java.lang.Long.TYPE == clazz) {
092                                                f.getFieldAccess().putLongValue(copy, 0L);
093                                        } else if (java.lang.Float.TYPE == clazz) {
094                                                f.getFieldAccess().putFloatValue(copy, 0.0F);
095                                        } else if (java.lang.Double.TYPE == clazz) {
096                                                f.getFieldAccess().putDoubleValue(copy, 0.0D);
097                                        }
098                                } else {
099                                        f.getFieldAccess().putValue(copy, null);
100                                }
101                        }
102                } catch (IllegalArgumentException e) {
103                        throw new IllegalStateException("Problem performing clone for field {" + f.getField().getName() + "} of object {" + System.identityHashCode(copy) + "}: " + e.getMessage(), e);
104                } catch (IllegalAccessException e) {
105                        throw new IllegalStateException("Problem performing clone for field {" + f.getField().getName() + "} of object {" + System.identityHashCode(copy) + "}: " + e.getMessage(), e);
106                }
107        }
108
109        @Override
110        protected <W> ClassModel<W> getClassModel(Class<W> clazz) {
111                return AsmClassAccess.get(clazz).getClassModel();
112        }
113
114        @Override
115        protected <T> void handleClonePrimitiveField(T obj, T copy, CloneDriver driver, FieldModel<T> f, IdentityHashMap<Object, Object> referencesToReuse) {
116
117                Field field = f.getField();
118
119                try {
120                        Class<?> clazz = f.getFieldClass();
121
122                        if (f.isPrivate()) {
123                                if (java.lang.Boolean.TYPE == clazz) {
124                                        field.setBoolean(copy, field.getBoolean(obj));
125                                } else if (java.lang.Byte.TYPE == clazz) {
126                                        field.setByte(copy, field.getByte(obj));
127                                } else if (java.lang.Character.TYPE == clazz) {
128                                        field.setChar(copy, field.getChar(obj));
129                                } else if (java.lang.Short.TYPE == clazz) {
130                                        field.setShort(copy, field.getShort(obj));
131                                } else if (java.lang.Integer.TYPE == clazz) {
132                                        field.setInt(copy, field.getInt(obj));
133                                } else if (java.lang.Long.TYPE == clazz) {
134                                        field.setLong(copy, field.getLong(obj));
135                                } else if (java.lang.Float.TYPE == clazz) {
136                                        field.setFloat(copy, field.getFloat(obj));
137                                } else if (java.lang.Double.TYPE == clazz) {
138                                        field.setDouble(copy, field.getDouble(obj));
139                                } else {
140                                        throw new IllegalStateException("Expected primitive but was :" + clazz.getName());
141                                }
142                        } else {
143                                if (java.lang.Boolean.TYPE == clazz) {
144                                        f.getFieldAccess().putBooleanValue(copy, field.getBoolean(obj));
145                                } else if (java.lang.Byte.TYPE == clazz) {
146                                        f.getFieldAccess().putByteValue(copy, field.getByte(obj));
147                                } else if (java.lang.Character.TYPE == clazz) {
148                                        f.getFieldAccess().putCharValue(copy, field.getChar(obj));
149                                } else if (java.lang.Short.TYPE == clazz) {
150                                        f.getFieldAccess().putShortValue(copy, field.getShort(obj));
151                                } else if (java.lang.Integer.TYPE == clazz) {
152                                        f.getFieldAccess().putIntValue(copy, field.getInt(obj));
153                                } else if (java.lang.Long.TYPE == clazz) {
154                                        f.getFieldAccess().putLongValue(copy, field.getLong(obj));
155                                } else if (java.lang.Float.TYPE == clazz) {
156                                        f.getFieldAccess().putFloatValue(copy, field.getFloat(obj));
157                                } else if (java.lang.Double.TYPE == clazz) {
158                                        f.getFieldAccess().putDoubleValue(copy, field.getDouble(obj));
159                                } else {
160                                        throw new IllegalStateException("Expected primitive but was :" + clazz.getName());
161                                }
162                        }
163
164                } catch (IllegalArgumentException e) {
165                        throw new IllegalStateException("Problem performing clone for field {" + field.getName() + "} of object {" + System.identityHashCode(obj) + "}: " + e.getMessage(), e);
166                } catch (IllegalAccessException e) {
167                        throw new IllegalStateException("Problem performing clone for field {" + field.getName() + "} of object {" + System.identityHashCode(obj) + "}: " + e.getMessage(), e);
168                }
169        }
170
171        @Override
172        protected <T> Object getFieldValue(T obj, FieldModel<T> f) {
173
174                final Field field = f.getField();
175
176                final Object fieldObject;
177
178                try {
179                        if (f.isPrivate()) {
180                                fieldObject = field.get(obj);
181                        } else {
182                                fieldObject = f.getFieldAccess().getValue(obj);
183                        }
184                } catch (IllegalArgumentException e) {
185                        throw new IllegalStateException("Problem performing clone for field {" + field.getName() + "} of object {" + System.identityHashCode(obj) + "}: " + e.getMessage(), e);
186                } catch (IllegalAccessException e) {
187                        throw new IllegalStateException("Problem performing clone for field {" + field.getName() + "} of object {" + System.identityHashCode(obj) + "}: " + e.getMessage(), e);
188                }
189
190                return fieldObject;
191        }
192
193        @Override
194        protected <T> void putFieldValue(T obj, FieldModel<T> f, Object value) {
195
196                final Field field = f.getField();
197
198                try {
199                        if (f.isPrivate()) {
200                                f.getField().set(obj, value);
201                        } else {
202                                f.getFieldAccess().putValue(obj, value);
203                        }
204                } catch (IllegalArgumentException e) {
205                        throw new IllegalStateException("Problem performing clone for field {" + field.getName() + "} of object {" + System.identityHashCode(obj) + "}: " + e.getMessage(), e);
206                } catch (IllegalAccessException e) {
207                        throw new IllegalStateException("Problem performing clone for field {" + field.getName() + "} of object {" + System.identityHashCode(obj) + "}: " + e.getMessage(), e);
208                }
209        }
210}