/******************************************************************************* * Copyright (c) 2010 Association for Decentralized Information Management in * Industry THTH ry. * 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: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.databoard.binding.reflection; import org.simantics.databoard.Bindings; import org.simantics.databoard.adapter.AdaptException; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.UnionBinding; import org.simantics.databoard.binding.error.BindingConstructionException; import org.simantics.databoard.binding.error.BindingException; import org.simantics.databoard.serialization.Serializer; import org.simantics.databoard.serialization.SpecializedSerializerProvider; import org.simantics.databoard.type.UnionType; /** * Bindings an abstract class with @Union annotation to a DataBoard's UnionType. * * Example of usage: * @Union({Rectangle.class, Circle.class, Triangle.class}) class Shape {} * * class Rectangle extends Shape { public int width, height; } * class Circle extends Shape { public int radius; } * class Triangle extends Shape { public int sideLength; } * * @author Toni Kalajainen */ class UnionClassBinding extends UnionBinding implements SpecializedSerializerProvider { Class[] componentClasses; Serializer specializedSerializer; public UnionClassBinding(UnionType type) throws BindingConstructionException { this.type = type; } @Override public Object create(int tag, Object value) { return value; } @Override public void setValue(Object union, int tag, Object value) throws BindingException { if (tag != getTag(union)) throw new BindingException("Cannot change the class of an instance"); Binding cb = getComponentBinding(tag); cb.readFrom(cb, value, union); } @Override public int getTag(Object obj) throws BindingException { for (int i=0; i c : componentClasses) if (c.isInstance(obj)) return true; return false; } @Override public Serializer getSpecializedSerializer() { return specializedSerializer; } transient Boolean isImmutable; @Override public synchronized boolean isImmutable() { if ( isImmutable == null ) { boolean b = true; for ( Binding cb : getComponentBindings() ) { b &= cb.isImmutable(); if (!b) break; } isImmutable = b; } return isImmutable; } @Override public Object readFromTry(Binding srcBinding, Object src, Object dst) throws BindingException { UnionBinding sb = (UnionBinding) srcBinding; int st = sb.getTag(src); int dt = getTag(dst); Binding scb = sb.getComponentBinding(st); Object sv = sb.getValue(src); if (st==dt) { // Same Tag Object dv = getValue(dst); Binding dcb = getComponentBinding(dt); dcb.readFrom(scb, sv, dv); return dv; } else { // Different Tag -> return cloned or (same, if immutable) value try { Binding dcb = getComponentBinding(st); return Bindings.adapt(src, scb, dcb); } catch(AdaptException e) { throw new BindingException(e); } } } /** * Returns true if the tag of this union type can be modified * * @return */ public boolean isTagMutable() { return true; } @Override protected boolean baseEquals(Object obj) { if (!super.baseEquals(obj)) return false; UnionClassBinding o = (UnionClassBinding)obj; if (isImmutable != o.isImmutable) return false; if (specializedSerializer != o.specializedSerializer) return false; if (componentClasses.length != o.componentClasses.length) return false; for (int i = 0; i < componentClasses.length; i++) { if (!componentClasses[i].equals(o.componentClasses[i])) return false; } return true; } @Override public int baseHashCode() { int code = super.baseHashCode(); for (int i = 0; i < componentClasses.length; i++) code = 23 * code + componentClasses.hashCode(); return code; } }