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}