/** * Copyright (c) 2016, All Contributors (see CONTRIBUTORS file) * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package com.eventsourcing.index; import com.eventsourcing.Entity; import com.eventsourcing.EntityHandle; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; public interface Attribute<O extends Entity, A> extends com.googlecode.cqengine.attribute.Attribute<EntityHandle<O>, A> { Class<O> getEffectiveObjectType(); default int calculateHashCode() { int result = getEffectiveObjectType().hashCode(); result = 31 * result + getAttributeType().hashCode(); result = 31 * result + getAttributeName().hashCode(); return result; } default boolean isEqual(Object o) { if (this == o) return true; if (!(o instanceof Attribute)) return false; Attribute that = (Attribute) o; // TODO: reinstate this cachedHashCode comparison once EqualsVerifier supports cached hash code "shortcut": //if (cachedHashCode != that.cachedHashCode) return false; if (!that.canEqual(this)) return false; if (!getAttributeName().equals(that.getAttributeName())) return false; if (!getAttributeType().equals(that.getAttributeType())) return false; if (!getEffectiveObjectType().equals(that.getEffectiveObjectType())) return false; return true; } default boolean canEqual(Object other) { return other instanceof Attribute; } static <O> Class<O> readGenericObjectType(Class<?> attributeClass, String attributeName) { try { ParameterizedType superclass = (ParameterizedType) attributeClass.getGenericSuperclass(); @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"}) Type actualType = superclass.getActualTypeArguments()[0]; Class<O> cls; if (actualType instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) actualType; @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"}) Class<O> actualClass = (Class<O>) parameterizedType.getRawType(); cls = actualClass; } else { @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"}) Class<O> actualClass = (Class<O>) actualType; cls = actualClass; } return cls; } catch (Exception e) { String attributeClassStr = attributeName .startsWith("<Unnamed attribute, class ") ? "" : " (" + attributeClass + ")"; throw new IllegalStateException( "Attribute '" + attributeName + "'" + attributeClassStr + " is invalid, cannot read generic type information from it. Attributes should typically EITHER be declared in code with generic type information as a (possibly anonymous) subclass of one of the provided attribute types, OR you can use a constructor of the attribute which allows the types to be specified manually."); } } }