package org.andork.q2; import org.andork.q2.QSpec.Property; /** * {@code QObject} (along with {@link QSpec}) provides the closest functionality * to reflection on a POJO that is possible without actually using reflection. * It also provides property {@linkplain #changeSupport() change support} that * will notify listeners of any property changes, so that you don't have to * write any boilerplate property change notification code.<br> * <br> * The Q doesn't stand for anything. * * @author andy.edwards * @param <S> * the type of {@link QSpec} for this object. */ public abstract class QObject<S extends QSpec> extends QElement { S spec; public QObject(S spec) { this.spec = spec; } public void addListener(QObjectListener listener) { super.addListener(listener); } protected abstract <T> T doGet(Property<T> property); protected abstract <T> T doSet(Property<T> property, T newValue); @Override public boolean equals(Object other) { return spec.equals(this, other); } protected void fireObjectChanged(Property<?> property, Object oldValue, Object newValue) { fireObjectChanged(property, oldValue, newValue, -1); } protected void fireObjectChanged(Property<?> property, Object oldValue, Object newValue, int index) { forEachListener(QObjectListener.class, l -> l.objectChanged(this, property, oldValue, newValue)); } public <T> T get(Property<T> property) { return property.get(this); } @Override public int hashCode() { return spec.hashCode(this); } public void removeListener(QObjectListener listener) { super.removeListener(listener); } public <T> T set(Property<T> property, T newValue) { return property.set(this, newValue); } public S spec() { return spec; } }