/*
* citygml4j - The Open Source Java API for CityGML
* https://github.com/citygml4j
*
* Copyright 2013-2017 Claus Nagel <claus.nagel@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.citygml4j.builder.copy;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashSet;
public abstract class CopyBuilder {
private HashSet<Class<?>> shallowCopy = new HashSet<Class<?>>();
private HashSet<Class<?>> nullCopy = new HashSet<Class<?>>();
public Object copy(final Object target) {
if (target instanceof String)
return copy((String)target);
else if (target instanceof Number)
return copy((Number)target);
else if (target instanceof Boolean)
return copy((Boolean)target);
else if (target instanceof Character)
return copy((Character)target);
else if (target instanceof Void)
return copy((Void)target);
else if (target instanceof Cloneable)
try {
return copyCloneable((Cloneable)target);
} catch (UnsupportedOperationException e) {
return target;
}
else
return target;
}
public void setShallowCopy(final Class<?>... c) {
for (final Class<?> item : c)
shallowCopy.add(item);
}
public void setNullCopy(final Class<?>... c) {
for (final Class<?> item : c)
nullCopy.add(item);
}
public void unsetShallowCopy(final Class<?>... c) {
for (final Class<?> item : c)
shallowCopy.remove(item);
}
public void unsetNullCopy(final Class<?>... c) {
for (final Class<?> item : c)
nullCopy.remove(item);
}
protected boolean isNullCopy(Object target) {
if (target == null)
return true;
if (nullCopy.contains(target.getClass()))
return true;
for (Class<?> c : target.getClass().getInterfaces())
if (nullCopy.contains(c))
return true;
return false;
}
protected boolean isShallowCopy(Object target) {
if (shallowCopy.contains(target.getClass()))
return true;
for (Class<?> c : target.getClass().getInterfaces())
if (shallowCopy.contains(c))
return true;
return false;
}
protected boolean shallowSetContains(Class<?> c) {
return shallowCopy.contains(c);
}
public String copy(String value) {
return value != null ? (nullCopy.contains(value.getClass()) ? null : value) : null;
}
public Number copy(Number value) {
return value != null ? (nullCopy.contains(value.getClass()) ? null : value) : null;
}
public Boolean copy(Boolean value) {
return value != null ? (nullCopy.contains(value.getClass()) ? null : value) : null;
}
public Character copy(Character value) {
return value != null ? (nullCopy.contains(value.getClass()) ? null : value) : null;
}
public Void copy(Void value) {
return value != null ? (nullCopy.contains(value.getClass()) ? null : value) : null;
}
public Class<?> copy(Class<?> value) {
return value != null ? (nullCopy.contains(value.getClass()) ? null : value) : null;
}
public long copy(long value) {
return value;
}
public int copy(int value) {
return value;
}
public short copy(short value) {
return value;
}
public char copy(char value) {
return value;
}
public byte copy(byte value) {
return value;
}
public double copy(double value) {
return value;
}
public float copy(float value) {
return value;
}
public boolean copy(boolean value) {
return value;
}
public Object[] copy(Object[] array) {
final Object[] copy = new Object[array.length];
for (int index = 0; index < array.length; index++) {
final Object item = array[index];
final Object itemCopy = copy(item);
copy[index] = itemCopy;
}
return copy;
}
public long[] copy(long[] array) {
final long[] copy = new long[array.length];
System.arraycopy(array, 0, copy, 0, array.length);
return copy;
}
public int[] copy(int[] array) {
final int[] copy = new int[array.length];
System.arraycopy(array, 0, copy, 0, array.length);
return copy;
}
public short[] copy(short[] array) {
final short[] copy = new short[array.length];
System.arraycopy(array, 0, copy, 0, array.length);
return copy;
}
public char[] copy(char[] array) {
final char[] copy = new char[array.length];
System.arraycopy(array, 0, copy, 0, array.length);
return copy;
}
public byte[] copy(byte[] array) {
final byte[] copy = new byte[array.length];
System.arraycopy(array, 0, copy, 0, array.length);
return copy;
}
public double[] copy(double[] array) {
final double[] copy = new double[array.length];
System.arraycopy(array, 0, copy, 0, array.length);
return copy;
}
public float[] copy(float[] array) {
final float[] copy = new float[array.length];
System.arraycopy(array, 0, copy, 0, array.length);
return copy;
}
public boolean[] copy(boolean[] array) {
final boolean[] copy = new boolean[array.length];
System.arraycopy(array, 0, copy, 0, array.length);
return copy;
}
public Object copyCloneable(Cloneable object) {
Method method = null;
try {
method = object.getClass().getMethod("clone", (Class[]) null);
} catch (NoSuchMethodException nsmex) {
method = null;
}
if (method == null || !Modifier.isPublic(method.getModifiers())) {
throw new UnsupportedOperationException(
"Could not clone object [" + object + "].",
new CloneNotSupportedException(
"Object class ["
+ object.getClass()
+ "] implements java.lang.Cloneable interface, "
+ "but does not provide a public no-arg clone() method. "
+ "By convention, classes that implement java.lang.Cloneable "
+ "should override java.lang.Object.clone() method (which is protected) "
+ "with a public method."));
}
final boolean wasAccessible = method.isAccessible();
try {
if (!wasAccessible) {
try {
method.setAccessible(true);
} catch (SecurityException ignore) {
//
}
}
return method.invoke(object, (Object[]) null);
} catch (Exception ex) {
throw new UnsupportedOperationException(
"Could not clone the object ["
+ object
+ "] as invocation of the clone() method has thrown an exception.",
ex);
} finally {
if (!wasAccessible) {
try {
method.setAccessible(false);
} catch (SecurityException ignore) {
//
}
}
}
}
}