From 2aefc9735068c62bc1d32d507282a83953af38be Mon Sep 17 00:00:00 2001 From: Sven Efftinge Date: Fri, 13 Feb 2015 08:49:34 +0100 Subject: [PATCH] [storage] allow nullable URIs. E.g. ReferenceDescription containerEObjectURI might be null if the reference is in a root eobject. Change-Id: I25a354ca8d05a97c24be34c65170167f37f5128e --- .../resource/persistence/PortableURIs.xtend | 18 ++--- .../SerializableResourceDescription.xtend | 12 +++- .../SerializableResourceDescriptionTest.xtend | 65 +++++++++++++++++++ 3 files changed, 85 insertions(+), 10 deletions(-) diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/resource/persistence/PortableURIs.xtend b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/resource/persistence/PortableURIs.xtend index df6dc1a65..7c093893a 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/resource/persistence/PortableURIs.xtend +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/resource/persistence/PortableURIs.xtend @@ -21,7 +21,7 @@ import org.eclipse.emf.ecore.util.EcoreUtil import org.eclipse.xtend.lib.annotations.Data import org.eclipse.xtext.naming.QualifiedName import org.eclipse.xtext.resource.IEObjectDescription -import org.eclipse.xtext.resource.IResourceServiceProvider +import org.eclipse.xtext.resource.impl.ResourceDescriptionsProvider import org.eclipse.xtext.scoping.IGlobalScopeProvider /** @@ -45,9 +45,8 @@ class PortableURIs { public static val PORTABLE_SCHEME = "portable" @Inject IGlobalScopeProvider globalScopeProvider -// @Inject LazyURIEncoder lazyURIencoder @Inject EPackage.Registry packageRegistry - @Inject IResourceServiceProvider.Registry resourceServiceProviderRegistry + @Inject ResourceDescriptionsProvider resourceDescriptionsProvider /** * @return whether the given string is a portable URI fragment @@ -89,9 +88,12 @@ class PortableURIs { */ def URI toPortableURI(StorageAwareResource sourceResource, URI targetURI) { val to = sourceResource.resourceSet.getResource(targetURI.trimFragment, false)?.getEObject(targetURI.fragment) - val result = toPortableURI(sourceResource, to); - if (result != null) { - return result + // if it points to some registered ecore, there's no resourceSet and the result is not portable + if (to == null || to.eResource.resourceSet != null) { + val result = toPortableURI(sourceResource, to); + if (result != null) { + return result + } } return null } @@ -121,8 +123,8 @@ class PortableURIs { * @return a portable URI fragment, or null if the give EObject isn't itself or is not contained in an exported EObjectDescription */ protected def String getPortableURIFragment(EObject obj) { - val serviceProvider = resourceServiceProviderRegistry.getResourceServiceProvider(EcoreUtil.getURI(obj)) - val desc = serviceProvider?.resourceDescriptionManager?.getResourceDescription(obj.eResource) + val descriptions = resourceDescriptionsProvider.getResourceDescriptions(obj.eResource) + val desc = descriptions.getResourceDescription(obj.eResource.URI) if (desc == null) { return null } diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/resource/persistence/SerializableResourceDescription.xtend b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/resource/persistence/SerializableResourceDescription.xtend index 02aaf3dc7..289f93c53 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/resource/persistence/SerializableResourceDescription.xtend +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/resource/persistence/SerializableResourceDescription.xtend @@ -242,11 +242,19 @@ package class SerializationExtensions { } def static URI readURI(ObjectInput in) { - return URI::createURI(in.readUTF) + val stringRep = in.readUTF + if (stringRep == "NULL") { + return null + } + return URI::createURI(stringRep) } def static void writeURI(ObjectOutput out, URI uri) { - out.writeUTF(uri.toString) + if (uri == null) { + out.writeUTF("NULL") + } else { + out.writeUTF(uri.toString) + } } def static QualifiedName readQualifiedName(ObjectInput in) { diff --git a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/resource/persistence/SerializableResourceDescriptionTest.xtend b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/resource/persistence/SerializableResourceDescriptionTest.xtend index 66d96da15..707d7219d 100644 --- a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/resource/persistence/SerializableResourceDescriptionTest.xtend +++ b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/resource/persistence/SerializableResourceDescriptionTest.xtend @@ -62,6 +62,11 @@ class SerializableResourceDescriptionTest { objectOut.writeObject(before) val in = new ObjectInputStream(new ByteArrayInputStream(bout.toByteArray)) val after = in.readObject as SerializableResourceDescription + + assertDescriptionsEqual(before, after) + } + + def void assertDescriptionsEqual(SerializableResourceDescription before, SerializableResourceDescription after) { assertEquals(before.URI, after.URI) assertEquals(before.importedNames, after.importedNames) @@ -86,4 +91,64 @@ class SerializableResourceDescriptionTest { assertEquals(beforeDesc.EObjectURI, afterDesc.EObjectURI) } } + + @Test def void testNullSafeSerialization() { + val uri = URI::createURI("file:/foo/bar.baz.foo") + val before = new SerializableResourceDescription => [ + URI = uri + references = #[ + new SerializableReferenceDescription => [ + sourceEObjectUri = uri.appendFragment('foo') + targetEObjectUri = null + containerEObjectURI = uri.appendFragment('baz') + EReference = EcorePackage.eINSTANCE.EAnnotation_Contents + indexInList = 1 + ], + new SerializableReferenceDescription => [ + sourceEObjectUri = null + targetEObjectUri = uri.appendFragment('hubble2') + containerEObjectURI = uri.appendFragment('baz2') + EReference = EcorePackage.eINSTANCE.EAnnotation_Contents + indexInList = 2 + ], + new SerializableReferenceDescription => [ + sourceEObjectUri = uri.appendFragment('foo') + targetEObjectUri = uri.appendFragment('hubble2') + containerEObjectURI = null + EReference = EcorePackage.eINSTANCE.EAnnotation_Contents + indexInList = 2 + ], + new SerializableReferenceDescription => [ + sourceEObjectUri = uri.appendFragment('foo') + targetEObjectUri = null + containerEObjectURI = null + EReference = EcorePackage.eINSTANCE.EAnnotation_Contents + indexInList = 2 + ], + new SerializableReferenceDescription => [ + sourceEObjectUri = null + targetEObjectUri = null + containerEObjectURI = null + EReference = EcorePackage.eINSTANCE.EAnnotation_Contents + indexInList = 2 + ] + ] + descriptions = #[ + new SerializableEObjectDescription => [ + EObjectURI = uri.appendFragment('baz') + qualifiedName = QualifiedName.create('foo','baz') + EClass = EcorePackage.eINSTANCE.EAttribute + userData = newHashMap('myKey' -> 'myValue') + ] + ] + importedNames = #[QualifiedName.create('foo'), QualifiedName.create('foo','bar')] + ] + + val bout = new ByteArrayOutputStream() + val objectOut = new ObjectOutputStream(bout) + objectOut.writeObject(before) + val in = new ObjectInputStream(new ByteArrayInputStream(bout.toByteArray)) + val after = in.readObject as SerializableResourceDescription + assertDescriptionsEqual(before, after) + } } \ No newline at end of file