org.eclipse.ocl.util.ObjectUtil Maven / Gradle / Ivy
/**
*
*
* Copyright (c) 2006, 2008, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM - Initial API and implementation
* Axel Uhl (SAP AG) - Bug 342644
*
*
*
* $Id: ObjectUtil.java,v 1.6 2011/05/01 10:56:50 auhl Exp $
*/
package org.eclipse.ocl.util;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import org.eclipse.emf.common.util.Enumerator;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.ocl.internal.evaluation.NumberUtil;
/**
* Certain generic utility operations on objects.
*
* @author Christian W. Damus (cdamus)
*/
public class ObjectUtil {
/**
* Computes the equivalence of two objects, accounting for primitive numeric
* values that OCL considers equal but Java does not. This is also safe
* when either value is null
.
*
* @param anObject an object or null
* @param anotherObject another object or null
*
* @return whether they are equivalent as far as OCL is concerned
*/
public static boolean equal(Object anObject, Object anotherObject) {
// if either value is undefined, the result is true just if both are
// undefined and false otherwise.
if (anObject == null || anotherObject == null) {
return anObject == anotherObject;
}
// primitive types
if (isPrimitive(anObject) || isPrimitive(anotherObject)) {
if (anObject instanceof Integer) {
anObject = NumberUtil.higherPrecisionNumber((Integer) anObject);
}
if (anotherObject instanceof Integer) {
anotherObject = NumberUtil.higherPrecisionNumber((Integer) anotherObject);
}
if (anObject instanceof Long && anotherObject instanceof Long) {
return ((Long) anObject).longValue() == ((Long) anotherObject).longValue();
} else if (anObject instanceof Long && anotherObject instanceof Double) {
return ((Long) anObject).doubleValue() == ((Double) anotherObject).doubleValue();
} else if (anObject instanceof Double && anotherObject instanceof Long) {
return ((Double) anObject).doubleValue() == ((Long) anotherObject).doubleValue();
} else if (anObject instanceof Double && anotherObject instanceof Double) {
return ((Double) anObject).doubleValue() == ((Double) anotherObject).doubleValue();
} else if (anObject instanceof String && anotherObject instanceof String) {
return anObject.equals(anotherObject);
} else if (anObject instanceof Boolean && anotherObject instanceof Boolean) {
return ((Boolean) anObject).booleanValue() == ((Boolean) anotherObject).booleanValue();
};
// if the types are incompatible the result is false
return false;
}
if ((anObject instanceof EEnumLiteral) && (anotherObject instanceof EEnumLiteral)) {
return anObject == anotherObject;
} else if ((anObject instanceof EEnumLiteral) && (anotherObject instanceof Enumerator)) {
return ((EEnumLiteral) anObject).getInstance() == anotherObject;
} else if ((anotherObject instanceof EEnumLiteral) && (anObject instanceof Enumerator)) {
return ((EEnumLiteral) anotherObject).getInstance() == anObject;
} else if ((anObject instanceof LinkedHashSet> && !(anotherObject instanceof LinkedHashSet>)) ||
(!(anObject instanceof LinkedHashSet>) && anotherObject instanceof LinkedHashSet>)) {
// a regular Java equals comparison would consider LinkedHashSets and Sets
// with equals contents equals. However, according to OCL 2.3 (OMG 10-11-42) section 11.7.1,
// two collections need to be of the same kind to be considered equal.
return false;
}
if (anObject instanceof LinkedHashSet>) {
// ...then so is anotherObject due to he above test.
// LinkedHashSet.equals doesn't consider ordering as it
// should for an OrderedSet implementation.
return orderedSetsEqual((LinkedHashSet>) anObject, (LinkedHashSet>) anotherObject);
}
return anObject.equals(anotherObject);
}
private static boolean orderedSetsEqual(LinkedHashSet> anObject,
LinkedHashSet> anotherObject) {
if (anObject == anotherObject) {
return true;
}
if (anObject.size() != anotherObject.size()) {
return false;
}
// inv: sizes are equal
if (anObject.isEmpty()) {
// then so is anotherObject because sizes are equal
return true;
}
Iterator> anObjectIter = anObject.iterator();
Iterator> anotherObjectIter = anotherObject.iterator();
while (anObjectIter.hasNext()) {
if (!equal(anObjectIter.next(), anotherObjectIter.next())) {
return false;
}
}
return true;
}
/**
* Computes hash of an object, accounting for the similar
* hashing of primitive numeric values that OCL considers equal but Java
* does not. It is also safe with null
values.
*
* @param anObject an object or null
*
* @return its OCL hash
*/
public static int hashCode(Object anObject) {
if (anObject == null) {
return 0;
}
if (isPrimitive(anObject)) {
// equal double and integer should hash the same
if (anObject instanceof Integer) {
return 37 * ((Integer) anObject).intValue();
} else if (anObject instanceof Long) {
return 37 * ((Long) anObject).intValue();
} else if (anObject instanceof Double) {
return 37 * ((Double) anObject).intValue();
} else if (anObject instanceof String) {
return anObject.hashCode();
} else if (anObject instanceof Boolean) {
return anObject.hashCode();
}
// shouldn't get here (there are no other OCL primitives)
return 0;
}
if (anObject instanceof EEnumLiteral) {
return ((EEnumLiteral) anObject).getInstance().hashCode();
}
return anObject.hashCode();
}
/**
* Queries whether the specified object represents an OCL primitive value.
*
* @param o an object
* @return whether it is an OCL primitive value
*/
public static boolean isPrimitive(Object o) {
return o instanceof Integer || o instanceof Long || o instanceof String
|| o instanceof Boolean || o instanceof Double;
}
/**
* Disposes of the specified object. If, in particular, it is
* an {@link EObject}, then it and all of its contents will have their
* adapter-lists cleared.
*
* @param object an object to dispose
*
* @since 1.2
*/
public static void dispose(Object object) {
if (object instanceof EObject) {
EObject eObject = (EObject) object;
eObject.eAdapters().clear();
for (Iterator iter = EcoreUtil.getAllContents(eObject,
false); iter.hasNext();) {
iter.next().eAdapters().clear();
}
} else if (object instanceof Collection>) {
for (Object next : ((Collection>) object)) {
dispose(next);
}
}
}
}