| Importing an extension onto an existing extension page aborts with an
{{IllegalArgumentException}}
when that page carries a legacy
{ExtensionCode.ExtensionVersionClass}}
object whose
property is empty. Nothing is imported: the page keeps its old metadata and the extension stays unusable by the Extension Manager. This affects old, hand-made extension pages created before the Repository Application managed them. They are precisely the pages that most need importing. Steps to reproduce 1. Take an extension page whose ExtensionCode.ExtensionClass.id is set, and which has an ExtensionCode.ExtensionVersionClass object with an empty version property. 2. Go to ExtensionCode.ImportExtension and import that extension id from a Maven repository. Reproduced on extensions.xwiki.org (XWiki 18.4.3) with Extension.Skin Extension Plugin, whose legacy version object had every property empty but download. Actual result
Failed to import extension: java.lang.IllegalArgumentException: An Entity Reference name cannot be null or empty
at org.xwiki.model.reference.EntityReference.setName(EntityReference.java:222)
at org.xwiki.model.reference.EntityReference.<init>(EntityReference.java:164)
at org.xwiki.model.reference.AbstractLocalizedEntityReference.<init>(AbstractLocalizedEntityReference.java:76)
at org.xwiki.model.reference.PageReference.<init>(PageReference.java:113)
at org.xwiki.model.reference.PageReference.<init>(PageReference.java:101)
at org.xwiki.repository.internal.ExtensionStore.getVersionDocument(ExtensionStore.java:503)
at org.xwiki.repository.internal.ExtensionStore.getExtensionVersionDocument(ExtensionStore.java:458)
at org.xwiki.repository.internal.ExtensionStore.getExtensionVersionDocument(ExtensionStore.java:441)
at org.xwiki.repository.internal.RepositoryManager.moveLegacyVersion(RepositoryManager.java:1925)
at org.xwiki.repository.internal.RepositoryManager.updateExtensionVersions(RepositoryManager.java:1024)
Expected result The import succeeds. A version object with a blank version carries no information and should simply be dropped, which is what the code already says it wants to do. Cause RepositoryManager.updateExtensionVersions (master, lines 859-872) decides to remove the object for any of three reasons, one of them being a blank version, and then migrates it to a dedicated version page whenever version-page mode is on – without re-checking that the version is non-blank:
if (versionPageEnabled || StringUtils.isBlank(version) || (versionProxyEnabled
&& !new DefaultVersion(version).equals(extension.getId().getVersion()))) {
extensionDocument.removeXObject(versionObject);
needSave = true;
if (versionPageEnabled) {
moveLegacyVersion(extensionDocument, versionObject);
}
moveLegacyVersion passes that blank version to ExtensionStore.getVersionDocument, which builds new PageReference(version, ...) and throws. The two conditions are always both true on a legacy page, because updateExtension calls extensionStore.setVersionPageEnabled(extensionObject) earlier in the same import – so versionPageEnabled is on by the time this loop runs, and every blank-version legacy object hits the failing branch. Suggested fix Only migrate an object that has a version to migrate:
if (versionPageEnabled && StringUtils.isNotBlank(version)) {
moveLegacyVersion(extensionDocument, versionObject);
}
A unit test in RepositoryManagerTest covering an extension document that carries a blank-version legacy version object would lock this in. |