blob: 5fbaec00252d82e3ecab55294038ec9a7eb8142f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2019 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* E.D.Willink - initial API and implementation
*******************************************************************************/
package org.eclipse.ocl.pivot.utilities;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.util.ECollections;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EModelElement;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
public class ClassUtil
{
private static final class EmptyIterator implements Iterator<Object>
{
@Override
public boolean hasNext() {
return false;
}
@Override
public Object next() {
throw new NoSuchElementException();
}
}
private static final @NonNull Iterator<?> EMPTY_ITERATOR = new EmptyIterator();
/**
* Return object cast to requiredClass.
* @param object to cast.
* @param requiredClass to cast to.
* @return cast object or null
*/
@SuppressWarnings("unchecked")
public static <T extends Object> @Nullable T asClassOrNull(Object object, Class<T> requiredClass) {
if (object == null)
return null;
if (requiredClass == null)
return null;
Class<?> objectClass = object.getClass();
if (!objectClass.isAssignableFrom(objectClass))
return null;
return (T) object;
}
/**
* Return object cast to T without a check.
* <p>
* This enables type-checking to be suppressed on a single expression term
* avoiding the need for suppressing unchecked warnings throughout the rest
* of an invoking method.
* <p>
* Use as: asClassUnchecked(object, (ArbitrarilyComplicatedType)null)
*
* @param <T> required type
* @param object to cast
* @param requiredClassObject dummy argument: use null
* @return cast type
*/
@SuppressWarnings("unchecked")
public static <T> T asClassUnchecked(Object object, T requiredClassObject) {
return (T) object;
}
/**
* Return object cast to T without a check.
* <p>
* This enables type-checking to suppressed on a single expression term
* avoiding the need for suppressing unchecked warnings throughout the rest
* of an invoking method.
* <p>
* Use as: ArbitrarilyComplicatedType castObject = asClassUnchecked(object);
*
* @param <T> required type
* @param object to cast
* @return cast type
*/
@SuppressWarnings("unchecked")
public static <T> T asClassUnchecked(Object object) {
return (T) object;
}
/**
* Return the DomainConstants.AS_METAMODEL_ANNOTATION_SOURCE for ePackage or null if none.
*/
public static @Nullable EAnnotation basicGetMetamodelAnnotation(@NonNull EPackage ePackage) {
EAnnotation asMetamodelAnnotation = ePackage.getEAnnotation(PivotConstants.AS_METAMODEL_ANNOTATION_SOURCE);
return asMetamodelAnnotation;
}
/**
* Return an iterator over no content. This replaces com.google.common.collect.Iterators.emptyIterator() for which no
* alternative exists on an adequate range of Guava versions.
*
* @since 1.3
*/
@SuppressWarnings("unchecked")
public static <T> @NonNull Iterator<T> emptyIterator() {
return (Iterator<T>) EMPTY_ITERATOR;
}
/**
* Return the non-null adapterClass if iAdfaptable has an adapterClass adapter.
*
* This method just delegates to IAdaptable.getAdapter() but avoids the hazard from the unconstrained Class&lt;T&gt; declaration.
*
* @since 1.1
*/
public static <T> @Nullable T getAdapter(@Nullable IAdaptable iAdaptable, @NonNull Class<T> adapterClass) {
return iAdaptable != null ? iAdaptable.getAdapter(adapterClass) : null;
}
public static <T> @Nullable T getAdapter(@NonNull Class<T> adapterClass, @NonNull Notifier notifier) {
List<Adapter> eAdapters = nonNullEMF(notifier.eAdapters());
return getAdapter(adapterClass, eAdapters);
}
public static <T> @Nullable T getAdapter(@NonNull Class<T> adapterClass, @NonNull List<Adapter> eAdapters) {
Adapter adapter = EcoreUtil.getAdapter(eAdapters, adapterClass);
if (adapter == null) {
return null;
}
if (!adapterClass.isAssignableFrom(adapter.getClass())) {
throw new ClassCastException(adapter.getClass().getName() + " is not assignable to " + adapterClass.getName());
}
@SuppressWarnings("unchecked")
T castAdapter = (T) adapter;
return castAdapter;
}
/**
* Return the fully typed class of an object.
* @param <T> type
* @param object the object
* @return the class
*/
@SuppressWarnings("unchecked")
public static <T> Class<T> getClass(T object) {
if (object == null)
return null;
return (Class<T>) object.getClass();
}
/**
* Return the sourceURI annotation of eModelElement, creating and installing it if required.
*/
public static @NonNull EAnnotation getEAnnotation(@NonNull EModelElement eModelElement, String sourceURI) {
EAnnotation eAnnotation = eModelElement.getEAnnotation(sourceURI);
if (eAnnotation == null) {
eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation();
eAnnotation.setSource(sourceURI);
eModelElement.getEAnnotations().add(eAnnotation);
}
return eAnnotation;
}
/**
* Return the DomainConstants.AS_METAMODEL_ANNOTATION_SOURCE for ePackage, creating it if needed.
*/
public static @NonNull EAnnotation getMetamodelAnnotation(@NonNull EPackage ePackage) {
EAnnotation eAnnotation = ePackage.getEAnnotation(PivotConstants.AS_METAMODEL_ANNOTATION_SOURCE);
if (eAnnotation == null) {
eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation();
eAnnotation.setSource(PivotConstants.AS_METAMODEL_ANNOTATION_SOURCE);
ePackage.getEAnnotations().add(eAnnotation);
}
return eAnnotation;
}
/**
* Return anObject cast to aClass if type-safe or null otherwise.
* @param anObject for which cast required
* @param aClass the type to which cast required
* @return the non-null cast of anObject if safe
*/
@SuppressWarnings("unchecked")
public static <T> @Nullable T isInstanceOf(Object anObject, Class<T> aClass) {
if (anObject == null)
return null;
Class<?> objectClass = anObject.getClass();
if (aClass.isAssignableFrom(objectClass))
return (T) anObject;
else
return null;
}
/**
* Return true if resource is a registered resource; hosting a compile Java model.
*/
public static boolean isRegistered(Resource resource) {
if (resource == null) {
return false;
}
return resource.getResourceSet() == null; // FIXME searching resource.getContents() for a derived EPackageImpl with an init() method is solider.
}
/**
* Check for an in appropriate program state. This should not happen, but is not impossible. For instance
* a Resource should be contained in a ResourceSet, but that doesn't mean it always is.
*<p>
* If the inappropriate state really cannot happen, an assertion should be used instead to avoid non-debug
* run-time cost.
* <p>
* Return aT, throwing an IllegalStateException if null.
* @since 1.1
*/
public static @NonNull <T> T nonNull(@Nullable T aT) {
assert aT != null;
return aT;
}
/**
* Return aT, checking the assertion that this call would not be necessary if EMF had comprehensive @NonNull annotations.
*/
public static @NonNull <T> T nonNullEMF(@Nullable T aT) {// FIXME remove once EMF guarantees non-null
assert aT != null;
return aT;
}
/**
* Check for an in appropriate model state which should have been detected by a model validation pass. Typical problems
* that nonNullModel detects are null mandatory model elements.
*<p>
* Return aT, checking the assertion that this call would not be necessary if the Ecore model was guaranteed to be valid.
*/
public static @NonNull <T> T nonNullModel(@Nullable T aT) {
assert aT != null; // FIXME Change to InvalidModelException
return aT;
}
/**
* Return aT, checking the assertion that this call would not be necessary if the Pivot model was guaranteed to be valid.
*/
public static @NonNull <T> T nonNullPivot(@Nullable T aT) {
assert aT != null; // FIXME Change to InvalidModelException
return aT;
}
/**
* Check for an in appropriate program state. This should not happen, but is not impossible. For instance
* a Resource should be contained in a ResourceSet, but that doesn't mean it always is.
*<p>
* If the inappropriate state really cannot happen, an assertion should be used instead to avoid non-debug
* run-time cost.
* <p>
* Return aT, throwing an IllegalStateException if null.
*/
public static @NonNull <T> T nonNullState(@Nullable T aT) {
if (aT == null) {
throw new IllegalStateException();
}
return aT;
}
/**
* Cast a logically nullFreeList such as EMF collection to a declared null free list.
* @since 1.1
*/
@SuppressWarnings("null")
public static <T> @NonNull List<@NonNull T> nullFree(@Nullable List<T> nullFreeList) {
return nullFreeList != null ? nullFreeList : Collections.emptyList();
}
/**
* @since 1.1
*/
@SuppressWarnings({"null", "unchecked"})
public static <T> @NonNull EList<@NonNull T> nullFree(@Nullable EList<T> nullFreeList) {
return nullFreeList != null ? nullFreeList : (EList<T>) ECollections.EMPTY_ELIST;
}
/**
* @since 1.10
*/
@SuppressWarnings({"null", "unchecked"})
public static <T> @NonNull Iterable<@NonNull T> nullFree(@Nullable Iterable<T> nullFreeList) {
return nullFreeList != null ? nullFreeList : (Iterable<T>) ECollections.EMPTY_ELIST;
}
/**
* Safely determines the relative order of <code>object</code> and
* <code>otherObject</code>, i.e. without throwing an exception if
* <code>object</code> is <code>null</code>.
*/
public static <T extends Comparable<T>> int safeCompareTo(@Nullable T object, @Nullable T otherObject) {
if (object == null) {
return otherObject == null ? 0 : 1;
}
else {
return otherObject == null ? -1 : object.compareTo(otherObject);
}
}
/**
* Safely determines whether <code>object</code> equals
* <code>otherObject</code>, i.e. without throwing an exception if
* <code>object</code> is <code>null</code>.
*
* @param object
* The first object to compare.
* @param otherObject
* The second object to compare.
* @return <code>true</code> if <code>object</code> equals
* <code>otherObject</code>; <code>false</code> otherwise.
*/
public static boolean safeEquals(@Nullable Object object, @Nullable Object otherObject) {
return object == null
? otherObject == null
: object.equals(otherObject);
}
/**
* Sort aList using comparator, using an Ecollections.sort if aLIst is an EList.
*/
public static <T> void sort(@NonNull List<? extends T> aList, @NonNull Comparator<T> comparator) {
if (aList.size() > 1) {
if (aList instanceof EList<?>) {
ECollections.sort((EList<? extends T>)aList, comparator);
}
else {
Collections.sort(aList, comparator);
}
}
}
/**
* @since 1.1
* @deprecated String.valueOf()now annotated to be @NonNull
*/
@Deprecated
public static @NonNull String toString(Object anObject) {
return String.valueOf(anObject);
}
}