001: /*
002: * Copyright 2007 JBoss Inc
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: *
016: * Created on Jul 5, 2007
017: */
018: package org.drools.util;
019:
020: import java.lang.reflect.Array;
021: import java.lang.reflect.Method;
022: import java.util.Collection;
023: import java.util.Collections;
024: import java.util.Map;
025:
026: /**
027: * A class with simple utility methods for shadowing
028: *
029: * @author etirelli
030: */
031: public class ShadowProxyUtils {
032:
033: /* Collections.UnmodifiableCollection is a package
034: * private class, thus the confusing bit above
035: * to get a Class to compare to. */
036: private static final Class UNMODIFIABLE_MAP = Collections
037: .unmodifiableMap(Collections.EMPTY_MAP).getClass();
038: private static final Class UNMODIFIABLE_COLLECTION = Collections
039: .unmodifiableCollection(Collections.EMPTY_LIST).getClass();
040:
041: private ShadowProxyUtils() {
042: }
043:
044: public static Object cloneObject(Object original) {
045: Object clone = null;
046: if (original instanceof Cloneable) {
047: try {
048: Method cloneMethod = original.getClass().getMethod(
049: "clone", new Class[0]);
050: clone = cloneMethod.invoke(original, new Object[0]);
051: } catch (Exception e) {
052: /* Failed to clone. Don't worry about it, and just return
053: * the original object. */
054: }
055: }
056:
057: if (clone == null) {
058: try {
059: if (original instanceof Map
060: && original != Collections.EMPTY_MAP
061: && !UNMODIFIABLE_MAP.isAssignableFrom(original
062: .getClass())) {
063:
064: /* empty and unmodifiable maps can't (and don't need to) be shadowed */
065: clone = original.getClass().newInstance();
066: ((Map) clone).putAll((Map) original);
067:
068: } else if (original instanceof Collection
069: && original != Collections.EMPTY_LIST
070: && original != Collections.EMPTY_SET
071: && !UNMODIFIABLE_COLLECTION
072: .isAssignableFrom(original.getClass())) {
073:
074: /* empty and unmodifiable collections can't (and don't need to) be shadowed */
075: clone = original.getClass().newInstance();
076: ((Collection) clone).addAll((Collection) original);
077:
078: } else if (original.getClass().isArray()) {
079: clone = cloneArray(original);
080: }
081:
082: } catch (Exception e) {
083: /* Failed to clone. Don't worry about it, and just return
084: * the original object. */
085: }
086: }
087:
088: if (clone == null) {
089: clone = original;
090: }
091:
092: return clone;
093: }
094:
095: public static Object cloneArray(Object original) {
096: Object result = null;
097:
098: if (original.getClass().isArray()) {
099: final int arrayLength = Array.getLength(original);
100:
101: if (arrayLength == 0) {
102: // empty arrays are immutable
103: result = original;
104: } else {
105: final Class componentType = original.getClass()
106: .getComponentType();
107:
108: // Even though arrays implicitly have a public clone(), it
109: // cannot be invoked reflectively, so need to do copy construction:
110: result = Array.newInstance(componentType, arrayLength);
111:
112: if (componentType.isArray()) {
113: for (int i = 0; i < arrayLength; i++) {
114: Array.set(result, i, cloneArray(Array.get(
115: original, i)));
116: }
117: } else {
118: System.arraycopy(original, 0, result, 0,
119: arrayLength);
120: }
121: }
122: }
123: return result;
124: }
125:
126: }
|