You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ni...@apache.org on 2011/01/08 15:09:48 UTC
svn commit: r1056709 - in /commons/proper/lang/branches/LANG_2_X/src:
main/java/org/apache/commons/lang/ObjectUtils.java
main/java/org/apache/commons/lang/exception/CloneFailedException.java
test/java/org/apache/commons/lang/ObjectUtilsTest.java
Author: niallp
Date: Sat Jan 8 14:09:48 2011
New Revision: 1056709
URL: http://svn.apache.org/viewvc?rev=1056709&view=rev
Log:
Port LANG-576 to LANG 2.x Branch - Add methods for cloneables to ObjectUtils
Added:
commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/exception/CloneFailedException.java (with props)
Modified:
commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/ObjectUtils.java
commons/proper/lang/branches/LANG_2_X/src/test/java/org/apache/commons/lang/ObjectUtilsTest.java
Modified: commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/ObjectUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/ObjectUtils.java?rev=1056709&r1=1056708&r2=1056709&view=diff
==============================================================================
--- commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/ObjectUtils.java (original)
+++ commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/ObjectUtils.java Sat Jan 8 14:09:48 2011
@@ -17,6 +17,11 @@
package org.apache.commons.lang;
import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+
+import org.apache.commons.lang.exception.CloneFailedException;
+import org.apache.commons.lang.reflect.MethodUtils;
/**
* <p>Operations on <code>Object</code>.</p>
@@ -307,6 +312,67 @@ public class ObjectUtils {
return c1 != null ? c1 : c2;
}
}
+
+ /**
+ * Clone an object.
+ *
+ * @param o the object to clone
+ * @return the clone if the object implements {@link Cloneable} otherwise <code>null</code>
+ * @throws CloneFailedException if the object is cloneable and the clone operation fails
+ * @since 2.6
+ */
+ public static Object clone(final Object o) {
+ if (o instanceof Cloneable) {
+ final Object result;
+ if (o.getClass().isArray()) {
+ final Class componentType = o.getClass().getComponentType();
+ if (!componentType.isPrimitive()) {
+ result = ((Object[])o).clone();
+ } else {
+ int length = Array.getLength(o);
+ result = Array.newInstance(componentType, length);
+ while (length-- > 0) {
+ Array.set(result, length, Array.get(o, length));
+ }
+ }
+ } else {
+ try {
+ result = MethodUtils.invokeMethod(o, "clone", null);
+ } catch (final NoSuchMethodException e) {
+ throw new CloneFailedException("Cloneable type "
+ + o.getClass().getName()
+ + " has no clone method: " + e);
+ } catch (final IllegalAccessException e) {
+ throw new CloneFailedException("Cannot clone Cloneable type "
+ + o.getClass().getName() + ": " + e);
+ } catch (final InvocationTargetException e) {
+ throw new CloneFailedException("Exception cloning Cloneable type "
+ + o.getClass().getName() + ": " + e.getTargetException());
+ }
+ }
+ return result;
+ }
+
+ return null;
+ }
+
+ /**
+ * Clone an object if possible. This method is similar to {@link #clone(Object)}, but will
+ * return the provided instance as the return value instead of <code>null</code> if the instance
+ * is not cloneable. This is more convenient if the caller uses different
+ * implementations (e.g. of a service) and some of the implementations do not allow concurrent
+ * processing or have state. In such cases the implementation can simply provide a proper
+ * clone implementation and the caller's code does not have to change.
+ *
+ * @param o the object to clone
+ * @return the clone if the object implements {@link Cloneable} otherwise the object itself
+ * @throws CloneFailedException if the object is cloneable and the clone operation fails
+ * @since 2.6
+ */
+ public static Object cloneIfPossible(final Object o) {
+ final Object clone = clone(o);
+ return clone == null ? o : clone;
+ }
// Null
//-----------------------------------------------------------------------
Added: commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/exception/CloneFailedException.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/exception/CloneFailedException.java?rev=1056709&view=auto
==============================================================================
--- commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/exception/CloneFailedException.java (added)
+++ commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/exception/CloneFailedException.java Sat Jan 8 14:09:48 2011
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.commons.lang.exception;
+
+/**
+ * Exception thrown when a clone cannot be created. In contrast to
+ * {@link CloneNotSupportedException} this is a {@link RuntimeException}.
+ *
+ * @author Apache Software Foundation
+ * @since 2.6
+ */
+public class CloneFailedException extends RuntimeException {
+ // ~ Static fields/initializers ---------------------------------------------
+
+ private static final long serialVersionUID = 20091223L;
+
+ // ~ Constructors -----------------------------------------------------------
+
+ /**
+ * Constructs a CloneFailedException.
+ *
+ * @param message description of the exception
+ * @since upcoming
+ */
+ public CloneFailedException(final String message) {
+ super(message);
+ }
+}
Propchange: commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/exception/CloneFailedException.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/exception/CloneFailedException.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Modified: commons/proper/lang/branches/LANG_2_X/src/test/java/org/apache/commons/lang/ObjectUtilsTest.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/branches/LANG_2_X/src/test/java/org/apache/commons/lang/ObjectUtilsTest.java?rev=1056709&r1=1056708&r2=1056709&view=diff
==============================================================================
--- commons/proper/lang/branches/LANG_2_X/src/test/java/org/apache/commons/lang/ObjectUtilsTest.java (original)
+++ commons/proper/lang/branches/LANG_2_X/src/test/java/org/apache/commons/lang/ObjectUtilsTest.java Sat Jan 8 14:09:48 2011
@@ -18,10 +18,14 @@ package org.apache.commons.lang;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
+import java.util.Arrays;
import java.util.Calendar;
import junit.framework.TestCase;
+import org.apache.commons.lang.exception.CloneFailedException;
+import org.apache.commons.lang.mutable.MutableObject;
+
/**
* Unit tests {@link org.apache.commons.lang.ObjectUtils}.
*
@@ -204,4 +208,104 @@ public class ObjectUtilsTest extends Tes
assertSame( minComparable, ObjectUtils.min( nonNullComparable1, minComparable ) );
assertSame( minComparable, ObjectUtils.min( minComparable, nonNullComparable1 ) );
}
+
+ /**
+ * Tests {@link ObjectUtils#clone(Object)} with a cloneable object.
+ */
+ public void testCloneOfCloneable() {
+ final CloneableString string = new CloneableString("apache");
+ final CloneableString stringClone = (CloneableString)ObjectUtils.clone(string);
+ assertEquals("apache", stringClone.getValue());
+ }
+
+ /**
+ * Tests {@link ObjectUtils#clone(Object)} with a not cloneable object.
+ */
+ public void testCloneOfNotCloneable() {
+ final String string = new String("apache");
+ assertNull(ObjectUtils.clone(string));
+ }
+
+ /**
+ * Tests {@link ObjectUtils#clone(Object)} with an uncloneable object.
+ */
+ public void testCloneOfUncloneable() {
+ final UncloneableString string = new UncloneableString("apache");
+ try {
+ ObjectUtils.clone(string);
+ fail("Thrown " + CloneFailedException.class.getName() + " expected");
+ } catch (final CloneFailedException e) {
+ //expected result
+ }
+ }
+
+ /**
+ * Tests {@link ObjectUtils#clone(Object)} with an object array.
+ */
+ public void testCloneOfStringArray() {
+ assertTrue(Arrays.equals(
+ new String[]{"string"}, (String[])ObjectUtils.clone(new String[]{"string"})));
+ }
+
+ /**
+ * Tests {@link ObjectUtils#clone(Object)} with an array of primitives.
+ */
+ public void testCloneOfPrimitiveArray() {
+ assertTrue(Arrays.equals(new int[]{1}, (int[])ObjectUtils.clone(new int[]{1})));
+ }
+
+ /**
+ * Tests {@link ObjectUtils#cloneIfPossible(Object)} with a cloneable object.
+ */
+ public void testPossibleCloneOfCloneable() {
+ final CloneableString string = new CloneableString("apache");
+ final CloneableString stringClone = (CloneableString)ObjectUtils.cloneIfPossible(string);
+ assertEquals("apache", stringClone.getValue());
+ }
+
+ /**
+ * Tests {@link ObjectUtils#cloneIfPossible(Object)} with a not cloneable object.
+ */
+ public void testPossibleCloneOfNotCloneable() {
+ final String string = new String("apache");
+ assertSame(string, ObjectUtils.cloneIfPossible(string));
+ }
+
+ /**
+ * Tests {@link ObjectUtils#cloneIfPossible(Object)} with an uncloneable object.
+ */
+ public void testPossibleCloneOfUncloneable() {
+ final UncloneableString string = new UncloneableString("apache");
+ try {
+ ObjectUtils.cloneIfPossible(string);
+ fail("Thrown " + CloneFailedException.class.getName() + " expected");
+ } catch (final CloneFailedException e) {
+ //expected result
+ }
+ }
+
+ /**
+ * String that is cloneable.
+ */
+ static final class CloneableString extends MutableObject implements Cloneable {
+ private static final long serialVersionUID = 1L;
+ CloneableString(final String s) {
+ super(s);
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return (CloneableString)super.clone();
+ }
+ }
+
+ /**
+ * String that is not cloneable.
+ */
+ static final class UncloneableString extends MutableObject implements Cloneable {
+ private static final long serialVersionUID = 1L;
+ UncloneableString(final String s) {
+ super(s);
+ }
+ }
+
}