Add methods for Cloneables to ObjectUtils (LANG-576).
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@908745 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
7a304cfc7b
commit
7b6ab58a01
|
@ -17,6 +17,10 @@
|
||||||
package org.apache.commons.lang3;
|
package org.apache.commons.lang3;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.exception.CloneFailedException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Operations on <code>Object</code>.</p>
|
* <p>Operations on <code>Object</code>.</p>
|
||||||
|
@ -310,6 +314,48 @@ public class ObjectUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clone an object.
|
||||||
|
*
|
||||||
|
* @param <T> the type of the 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 3.0
|
||||||
|
*/
|
||||||
|
public static <T> T clone(final T o) {
|
||||||
|
if (o instanceof Cloneable) {
|
||||||
|
try {
|
||||||
|
final Method clone = o.getClass().getMethod("clone", (Class[])null);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
final T result = (T)clone.invoke(o, (Object[])null);
|
||||||
|
return result;
|
||||||
|
} catch (final NoSuchMethodException e) {
|
||||||
|
throw new CloneFailedException("Cloneable type has no clone method", e);
|
||||||
|
} catch (final IllegalAccessException e) {
|
||||||
|
throw new CloneFailedException("Cannot clone Cloneable type", e);
|
||||||
|
} catch (final InvocationTargetException e) {
|
||||||
|
throw new CloneFailedException("Exception cloning Cloneable type", e.getCause());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clone an object if possible.
|
||||||
|
*
|
||||||
|
* @param <T> the type of the object
|
||||||
|
* @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 3.0
|
||||||
|
*/
|
||||||
|
public static <T> T cloneIfPossible(final T o) {
|
||||||
|
final T clone = clone(o);
|
||||||
|
return clone == null ? o : clone;
|
||||||
|
}
|
||||||
|
|
||||||
// Null
|
// Null
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* 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.lang3.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when a clone cannot be created. In contrast to
|
||||||
|
* {@link CloneNotSupportedException} this is a {@link RuntimeException}.
|
||||||
|
*
|
||||||
|
* @author Apache Software Foundation
|
||||||
|
* @since 3.0
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a CloneFailedException.
|
||||||
|
*
|
||||||
|
* @param cause cause of the exception
|
||||||
|
* @since upcoming
|
||||||
|
*/
|
||||||
|
public CloneFailedException(final Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a CloneFailedException.
|
||||||
|
*
|
||||||
|
* @param message description of the exception
|
||||||
|
* @param cause cause of the exception
|
||||||
|
* @since upcoming
|
||||||
|
*/
|
||||||
|
public CloneFailedException(final String message, final Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,6 +21,9 @@ import java.lang.reflect.Modifier;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.exception.CloneFailedException;
|
||||||
|
import org.apache.commons.lang3.mutable.MutableObject;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -212,4 +215,89 @@ public class ObjectUtilsTest extends TestCase {
|
||||||
assertNull( ObjectUtils.min((String)null, (String)null) );
|
assertNull( ObjectUtils.min((String)null, (String)null) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link ObjectUtils#clone(Object)} with a cloneable object.
|
||||||
|
*/
|
||||||
|
public void testCloneOfCloneable() {
|
||||||
|
final CloneableString string = new CloneableString("apache");
|
||||||
|
final CloneableString stringClone = 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) {
|
||||||
|
assertEquals(NoSuchMethodException.class, e.getCause().getClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link ObjectUtils#cloneIfPossible(Object)} with a cloneable object.
|
||||||
|
*/
|
||||||
|
public void testPossibleCloneOfCloneable() {
|
||||||
|
final CloneableString string = new CloneableString("apache");
|
||||||
|
final CloneableString stringClone = 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) {
|
||||||
|
assertEquals(NoSuchMethodException.class, e.getCause().getClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String that is cloneable.
|
||||||
|
*/
|
||||||
|
static final class CloneableString extends MutableObject<String> implements Cloneable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
CloneableString(final String s) {
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CloneableString clone() throws CloneNotSupportedException {
|
||||||
|
return (CloneableString)super.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String that is not cloneable.
|
||||||
|
*/
|
||||||
|
static final class UncloneableString extends MutableObject<String> implements Cloneable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
UncloneableString(final String s) {
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue