From 172dfc5baf5ccf07c8cc6039f6653c84f320576f Mon Sep 17 00:00:00 2001 From: Simon Barner <barner@fortiss.org> Date: Mon, 8 Sep 2014 15:21:17 +0000 Subject: [PATCH] - Avoid unbounded recursion in DynamicInstanceAnnotationValueProviderBase - Fix editing of dynamically instantiated annotations refs 1841 --- ...iInstanceAnnotationTextEditingSupport.java | 17 ++++++- ...icInstanceAnnotationValueProviderBase.java | 26 ++++++---- .../view/CreateAnnotationInstanceColumn.java | 48 ++++++++++++++----- 3 files changed, 70 insertions(+), 21 deletions(-) diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/editingsupport/MultiInstanceAnnotationTextEditingSupport.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/editingsupport/MultiInstanceAnnotationTextEditingSupport.java index 5f2f22e10..725b23a29 100644 --- a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/editingsupport/MultiInstanceAnnotationTextEditingSupport.java +++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/editingsupport/MultiInstanceAnnotationTextEditingSupport.java @@ -20,6 +20,7 @@ package org.fortiss.tooling.base.ui.annotation.editingsupport; import org.eclipse.jface.viewers.ColumnViewer; import org.fortiss.tooling.base.model.element.IAnnotatedSpecification; import org.fortiss.tooling.base.ui.annotation.AnnotationEntry; +import org.fortiss.tooling.base.ui.annotation.IAnnotationValueService; import org.fortiss.tooling.base.ui.annotation.valueprovider.DynamicInstanceAnnotationValueProviderBase; /** @@ -63,7 +64,21 @@ public class MultiInstanceAnnotationTextEditingSupport extends TextEditingSuppor protected boolean canEdit(Object element) { if(element instanceof AnnotationEntry) { AnnotationEntry data = (AnnotationEntry)element; - return data.getSpecificationValue(specClass, instanceKey) != null; + + // Check if a value already exists. + if(data.getSpecificationValue(specClass, instanceKey) != null) { + return true; + } + + // For dynamically instantiated annotations, check if the key exists with at least one + // model element. + for(AnnotationEntry entry : IAnnotationValueService.INSTANCE.getValues(data + .getModelElement())) { + + if(entry.getInstanceKeys(specClass).contains(instanceKey)) { + return true; + } + } } return true; diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/DynamicInstanceAnnotationValueProviderBase.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/DynamicInstanceAnnotationValueProviderBase.java index 5b0be31cf..262aeaf67 100644 --- a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/DynamicInstanceAnnotationValueProviderBase.java +++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/DynamicInstanceAnnotationValueProviderBase.java @@ -81,11 +81,12 @@ public abstract class DynamicInstanceAnnotationValueProviderBase<T extends IAnno } /** {@inheritDoc} */ - @SuppressWarnings("unchecked") @Override - public <V> V getAnnotationValue(T spec, String instanceKey) throws Exception { + public <V> V getAnnotationValue(T specification, String instanceKey) throws Exception { // Return value of current instance (entry map containing all instances of the annotation) - return ((EMap<String, V>)getAnnotationValue(spec)).get(instanceKey); + EMap<String, V> map = super.getAnnotationValue(specification, DEFAULT_KEY); + + return map.get(instanceKey); } @@ -97,19 +98,28 @@ public abstract class DynamicInstanceAnnotationValueProviderBase<T extends IAnno private <V> void setAnnotationValueFromString(String value, T specification, String instanceKey) throws Exception { - ((EMap<String, V>)getAnnotationValue(specification)).put(instanceKey, - (V)valueFactory.createFromString(valueDataType, value)); + EMap<String, V> map = super.getAnnotationValue(specification, DEFAULT_KEY); + + V val = (V)valueFactory.createFromString(valueDataType, value); + if(val == null) { + val = (V)valueDataType.getDefaultValue(); + } + if(val == null) { + val = (V)valueFactory.createFromString(valueDataType, "0"); + } + + map.put(instanceKey, val); } /** {@inheritDoc} */ - @SuppressWarnings("unchecked") @Override public <V> void setAnnotationValue(V value, T specification, String instanceKey) throws Exception { if(value instanceof String) { setAnnotationValueFromString((String)value, specification, instanceKey); } else { - ((EMap<String, V>)getAnnotationValue(specification)).put(instanceKey, value); + EMap<String, V> map = super.getAnnotationValue(specification, DEFAULT_KEY); + map.put(instanceKey, value); } } @@ -136,7 +146,7 @@ public abstract class DynamicInstanceAnnotationValueProviderBase<T extends IAnno EMap<String, ?> kVMap = null; try { - kVMap = getAnnotationValue(specification); + kVMap = super.getAnnotationValue(specification, DEFAULT_KEY); } catch(Exception e) { // Ignore exception } diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/CreateAnnotationInstanceColumn.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/CreateAnnotationInstanceColumn.java index fff800606..43fc8bc79 100644 --- a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/CreateAnnotationInstanceColumn.java +++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/CreateAnnotationInstanceColumn.java @@ -20,6 +20,8 @@ package org.fortiss.tooling.base.ui.annotation.view; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.notify.impl.NotificationImpl; import org.eclipse.emf.common.util.EMap; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.jface.dialogs.IInputValidator; import org.eclipse.jface.dialogs.InputDialog; import org.eclipse.jface.dialogs.MessageDialog; @@ -44,6 +46,7 @@ import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; import org.fortiss.tooling.base.model.element.IAnnotatedSpecification; import org.fortiss.tooling.base.ui.annotation.AnnotationEntry; +import org.fortiss.tooling.base.ui.annotation.IAnnotationValueService; import org.fortiss.tooling.kernel.extension.data.ITopLevelElement; import org.fortiss.tooling.kernel.service.IPersistencyService; @@ -224,21 +227,42 @@ public class CreateAnnotationInstanceColumn extends ViewerColumn { .getModelElement()); modelContext.runAsCommand(new Runnable() { - @SuppressWarnings("unchecked") @Override public void run() { try { - // Work around the fact that getSpecificationValue(null, - // columnSpec.getClass(), instanceKey) would resolve - // to the more specific getSpecificationValue(String, Class<? - // extends IAnnotatedSpecification>, String) overload of the method, - // and thus would not work for maps whose value type is not String. - // - // Hence, the entire instance map is retrieved here, and put() is - // called explicitly. - ((EMap<String, ?>)columnSpecAnnEntry - .getSpecificationValue(columnSpec.getClass())).put( - instanceKey, null); + // Populate new instance (in order to make the corresponding cells + // editable + String value = ""; + if(!columnSpec.eClass().getEStructuralFeatures().isEmpty()) { + EStructuralFeature dynamicInstanceFeature = + columnSpec.eClass().getEStructuralFeatures().get(0); + + // Annotations that can be dynamically instantiated are + // implemented using an appropriate EMap. + if(dynamicInstanceFeature.getEType().getInstanceTypeName() + .equals("java.util.Map$Entry")) { + + // Determine value type + EStructuralFeature valueFeature = + ((EClass)dynamicInstanceFeature.getEType()) + .getEStructuralFeature("value"); + if(Number.class.isAssignableFrom(valueFeature.getEType() + .getInstanceClass())) { + + // Initialize numbers with 0 + // (initialization fails with "") + value = "0"; + } + } + + } + + for(AnnotationEntry entry : IAnnotationValueService.INSTANCE + .getValues(columnSpecAnnEntry.getModelElement())) { + + entry.setSpecificationValue(value, columnSpec.getClass(), + instanceKey); + } // Inform others, e.g. the respective annotation view that a new // instance of this annotation has been created. -- GitLab