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;
017
018import java.lang.invoke.MethodHandle;
019import java.util.Collections;
020import java.util.IdentityHashMap;
021import java.util.Set;
022
023import org.jadira.reflection.access.unsafe.UnsafeOperations;
024import org.jadira.reflection.cloning.api.CloneDriver;
025import org.jadira.reflection.cloning.api.CloneImplementor;
026import org.jadira.reflection.cloning.api.Cloner;
027import org.jadira.reflection.cloning.implementor.PortableCloneStrategy;
028import org.jadira.reflection.cloning.implementor.UnsafeCloneStrategy;
029import org.objenesis.ObjenesisException;
030
031/**
032 * This is a highly reduced version of {@link Cloner}. It can deliver somewhat better throughput
033 * than {@link UnsafeCloneStrategy} using the Server JVM, and around twice the throughput of the
034 * {@link PortableCloneStrategy}. Unlike BasicCloner, this cloner does not offer any configuration
035 * options. Due to lack of configuration and special functions, this cloner is unsuitable for many
036 * datatypes.
037 * 
038 * Note that MinimalCloner can be slower for certain kinds of data structure. For example, when
039 * cloning a linked list, MinimalCloner must visit all the references of the entire data structure,
040 * whereas other Cloners can use a CloneImplementor to perform efficient cloning of this structure
041 * iteratively.
042 * 
043 * In general, you are recommended to use MinimalCloner judiciously. Typically you can use it by
044 * designating a data type as @Cloneable(implementor=MinimalCloner.class) so that the type known to
045 * benefit from this cloner makes use of it.
046 */
047public class MinimalCloner implements Cloner, CloneDriver, CloneImplementor {
048
049        private static final UnsafeOperations UNSAFE_OPERATIONS = UnsafeOperations.getUnsafeOperations();
050
051        @Override
052        public <T> T newInstance(Class<T> c) {
053                try {
054                        return UNSAFE_OPERATIONS.allocateInstance(c);
055                } catch (IllegalStateException e) {
056                        throw new ObjenesisException(e.getCause());
057                }
058        }
059
060        /**
061         * Always returns true
062         */
063        @Override
064        public boolean canClone(Class<?> clazz) {
065                return true;
066        }
067
068        @Override
069        public <T> T clone(T obj, CloneDriver context, IdentityHashMap<Object, Object> referencesToReuse, long stackDepth) {
070
071                T copy = UNSAFE_OPERATIONS.deepCopy(obj, referencesToReuse);
072                return copy;
073        }
074
075        /**
076         * This implementation does not delegate to implementors
077         */
078        @Override
079        public CloneImplementor getImplementor(Class<?> clazz) {
080                return null;
081        }
082
083        /**
084         * This implementation cannot invoke clone()
085         */
086        @Override
087        public boolean isUseCloneable() {
088                return false;
089        }
090
091        /**
092         * Transient fields are always cloned
093         */
094        @Override
095        public boolean isCloneTransientFields() {
096                return true;
097        }
098
099        /**
100         * Transient annotated fields are always cloned
101         */
102        @Override
103        public boolean isCloneTransientAnnotatedFields() {
104                return true;
105        }
106
107        /**
108         * Immutable fields are always cloned, but object reference identity in the new structure is
109         * preserved
110         */
111        @Override
112        public boolean isCloneImmutable() {
113                return true;
114        }
115
116        /**
117         * No Immutable classes are identified
118         */
119        @Override
120        public Set<Class<?>> getImmutableClasses() {
121                return Collections.emptySet();
122        }
123
124        /**
125         * No Non-Cloneable classes are identified
126         */
127        @Override
128        public Set<Class<?>> getNonCloneableClasses() {
129                return Collections.emptySet();
130        }
131
132        /**
133         * CloneImplementors may not be used
134         */
135        @Override
136        public boolean isUseCloneImplementors() {
137                return false;
138        }
139
140        @Override
141        public <T> T clone(T obj) {
142                return clone(obj, this, new IdentityHashMap<Object, Object>(), 0L);
143        }
144
145        @Override
146        public void initialiseFor(Class<?> classes) {
147        }
148
149        /**
150         * Cloneable annotation is not supported
151         */
152        @Override
153        public CloneImplementor getAnnotationImplementor(Class<?> clazz) {
154                return null;
155        }
156
157        /**
158         * Cloneable interface is not supported
159         */
160        @Override
161        public MethodHandle getCloneMethod(Class<?> clazz) {
162                return null;
163        }
164
165        /**
166         * Does not clone synthetic fields
167         */
168        @Override
169        public boolean isCloneSyntheticFields() {
170                return false;
171        }
172
173        @Override
174        public void putAnnotationImplementor(Class<?> clazz, CloneImplementor implementor) {
175                // No-op
176        }
177
178        @Override
179        public void putCloneMethod(Class<?> clazz, MethodHandle handle) {
180                // No-op
181        }
182
183        @Override
184        public CloneImplementor getBuiltInImplementor(Class<?> clazz) {
185                return null;
186        }
187
188        @Override
189        public boolean isImmutableInstance(Object instance) {
190                return false;
191        }
192
193        @Override
194        public void putImmutableInstance(Object instance) {
195                // no-op
196        }
197
198        @Override
199        public boolean isTrackReferences() {
200                return true;
201        }
202
203        @Override
204        public boolean isTrackReferencesForFlatClasses() {
205                return true;
206        }
207}