Preparing for Confluence 9.0 - EAP out now

Hi folks,

while developing locally using the Confluence 9, I encountered an issue where, after uploading an attachment to a Confluence page, I can view and download the file as expected. However, when I shut down the server and restart it, the attachment remains listed in the attachment overview of the page, but attempting to download it results in a file named attachmentNotFound.html being downloaded instead of the actual attachment.

In previous versions, this problem did not occur—the attachments remained accessible even after restarting the server.

This issue is particularly concerning because it raises the risk that users might lose their progress after a server restart which is only saved in files within Confluence.

Could you please help me with this?
Thank you in advance!

1 Like

Testing in Confluence 9.0.3 using the official docker image, I cannot reproduce this.

What does the log file say?

Something may be different in your instance. Perhaps it helps if you provide step by step instructions how you tested it.

Hey Metin,

thanks for testing it out already with the official docker image.
I’m using the Atlassian Plugin SDK and start Confluence 9.0.3 using the atlas-run command.
I then upload the attachment to a page. Afterwards, I shut down the server via the console using Ctrl+C. Then I restart the server with atlas-run and try to download the attachment via the UI.
The console logs the following error:

WARN [http-nio-1990-exec-8 url: /confluence/download/attachments/1048578/uploaded.bpmn; user: admin] [confluence.pages.DefaultAttachmentManager] getAttachmentData Could not find data for attachment: Attachment: uploaded.bpmn v.1 (1048579) admin - com.atlassian.confluence.pages.persistence.dao.filesystem.AttachmentDataFileSystemException: No such file for Attachment: uploaded.bpmn v.1 (1048579) admin. Were looking at ${confluenceHome}\attachments\v4\19\0\1048579\1048579.1

Again, with Confluence versions before Confluence 9 this worked.
Can someone reproduce this and help me with it?

As far as I know, com.atlassian.confluence.importexport.impl package is not exported via osgi in Confluence 9, at least we have an error that classes from that package are not found. The replacement suggested is the BackupRestoreManager component, but with this one we cannot export a single page to HTML. Is there any solution to export a single page to HTML via api ?

Thx!

2 Likes

Have you checked if the directory and file exist and how the file attributes look? It may be an access problem. Do you start Confluence with the same user in both situations (initial start and restart)?

Other than that, I can’t help because I’m not on Windows, sorry.

We have worked our way through converting our backend code for Confluence 9 and it can now be built and installed without error. However, our velocity templates do not load any of the resources marked as $webResourceManager.requireResource().

We currently use the atlassian-webresource-webpack-plugin library to build our front-end resources which means our web resources are defined in the webpack.config.js file rather than the atlassian-plugin.xml file.

On navigation to the configuration page for the app, the page title loads but then nothing. No console errors, no backend errors, nothing.

Things I have tried:

  • permittedMethods have been added to the xwork definitions.
  • atlassian.velocity.method.allowlist.debug has been set as I thought it could be the VM files but no errors are logged.
  • dependencies have been upgraded in the package.json making no difference. I am currently back using:
"devDependencies": {
...
"webpack": "^5.76.2",
"webpack-cli": "4.9.2",
"webpack-merge": "^4.1.4",
"webpack-sources": "^1.1.0"
}
"dependencies": {
...
"atlassian-webresource-webpack-plugin": "^5.2.8"
}

This entire process has been exhausting.

I did find this metadata file Bitbucket which suggests that libraries may have been moved around, but the webpack-plugin does seem to still rely on the old format of using -rest and not -api as the repo might suggest.

This is our current providedDependencies.json file

mappings
    .set("jquery", {
        dependency: ["com.atlassian.plugins.jquery:jquery"],
        import: {
            "amd": "jquery",
            "var": "jQuery"
        }
    })
    .set("wrm/require", {
        dependency: ["com.atlassian.plugins.atlassian-plugins-webresource-rest:web-resource-manager"],
        import: {
            "amd": "wrm/require",
            "var": "WRM.require"
        }
    })
    .set("wrm/data", {
        dependency: ["com.atlassian.plugins.atlassian-plugins-webresource-plugin:data"],
        import: {
            "amd": "wrm/data",
            "var": "WRM.data"
        }
    })
    .set("wrm/context-path", {
        dependency: ["com.atlassian.plugins.atlassian-plugins-webresource-plugin:context-path"],
        import: {
            "amd": "wrm/context-path",
            "var": "AJS.contextPath"
        }
    });

Is anyone else using atlassian-webresource-webpack-plugin and has migrated successfully?

Hi everyone,

We’ve finally succeeded in building a JAR that runs across Confluence 7 to 9. It took us approximately 95 person-hours, and it was quite a challenging process. This thread was invaluable in resolving some issues, so I’d like to share some key learnings from our experience.


Key Challenge: The Rest Api

The biggest hurdle we faced was adapting our REST APIs. Different versions of Confluence export different versions of Jackson, which caused significant issues since our application also relies heavily on Jackson internally. To resolve this, we chose to package Jackson directly into our app instead of importing it via OSGi. A similar approach was necessary for Jakarta Validation.

To achieve compatibility across Confluence versions 7 to 9, we decided to move away from some of the “Magic.” Instead of relying on implicit serialization, deserialization, and validation by Confluence/Spring, we now receive the request body as an InputStream and handle serialization explicitly using our own packaged Jackson. We also replaced the @AdminOnly annotation for security checks with explicit code, moving this logic to a dedicated bean. This is necessary because confluence 7 and 9 need different imports for AdminOnly. Although these changes might not be considered as elegant, it has significantly improved our code’s maintainability, debuggability, and portability.


Approach to Making the REST APIs Compatible Across Versions

1. Explicit Import-Package Declarations

  • We made all Import-Package statements explicit in our configuration. By avoiding large wildcard imports, we ensured that only the desired classes were included in the classpath. Specifically, we avoided importing anything related to Jackson or Jakarta Validation.

  • Here is our Import-Package statement for reference:

    <plugin>
        <groupId>com.atlassian.maven.plugins</groupId>
        <artifactId>confluence-maven-plugin</artifactId>
        <version>9.0.2</version>
        <extensions>true</extensions>
        <configuration>
            [...]
            <Import-Package>
                com.atlassian.confluence.api.model.content.id,
                com.atlassian.upm.api.license.entity,
                com.atlassian.bandana,
                com.atlassian.bonnie,
                com.atlassian.confluence.api.model.content,
                com.atlassian.confluence.api.service.accessmode,
                com.atlassian.confluence.api.service.content,
                com.atlassian.confluence.api.service.exceptions,
                com.atlassian.confluence.api.service.search,
                com.atlassian.confluence.content,
                com.atlassian.confluence.core,
                com.atlassian.confluence.event.events.content.comment,
                com.atlassian.confluence.importexport.resource,
                com.atlassian.confluence.labels,
                com.atlassian.confluence.pages,
                com.atlassian.confluence.pages.persistence.dao,
                com.atlassian.confluence.pages.thumbnail,
                com.atlassian.confluence.plugins.conversion.api,
                com.atlassian.confluence.renderer.radeox.macros,
                com.atlassian.confluence.search,
                com.atlassian.confluence.search.service,
                com.atlassian.confluence.search.v2,
                com.atlassian.confluence.search.v2.query,
                com.atlassian.confluence.search.v2.sort,
                com.atlassian.confluence.security,
                com.atlassian.confluence.setup.bandana,
                com.atlassian.confluence.setup.settings,
                com.atlassian.confluence.spaces,
                com.atlassian.confluence.user,
                com.atlassian.confluence.util,
                com.atlassian.confluence.util.i18n,
                com.atlassian.confluence.util.velocity,
                com.atlassian.confluence.xhtml.api,
                com.atlassian.event.api,
                com.atlassian.plugin,
                com.atlassian.plugin.web,
                com.atlassian.renderer.util,
                com.atlassian.sal.api.transaction,
                com.atlassian.sal.api.user,
                com.atlassian.scheduler,
                com.atlassian.spring.container,
                com.atlassian.plugin.spring.scanner.annotation.export,
                com.atlassian.plugin.spring.scanner.annotation.imports,
                com.atlassian.upm.api.license,
                com.atlassian.upm.api.util,
                com.atlassian.user,
                com.atlassian.user.search,
                com.atlassian.user.search.page,
                com.atlassian.user.search.query,
                javax.net,
                javax.net.*,
                javax.imageio,
                javax.servlet,
                javax.servlet.*,
                javax.ws.*,
                javax.xml,
                javax.xml.*,
                javax.swing,
                org.xml.*,
                org.springframework.beans,
                org.springframework.beans.factory,
                org.springframework.beans.factory.annotation,
                org.springframework.cglib.core,
                org.springframework.cglib.proxy,
                org.springframework.cglib.reflect,
                org.springframework.stereotype,
                org.springframework.context.annotation,
                org.springframework.web.bind.annotation,
                com.opensymphony.xwork2.conversion.impl;resolution:=optional,
                org.springframework.osgi.*;resolution:="optional",
                org.eclipse.gemini.blueprint.*;resolution:="optional",
                org.osgi.framework,
                org.slf4j
            </Import-Package>
            <!-- Ensure plugin is spring powered -->
            <Spring-Context>*</Spring-Context>
        </configuration>
    </plugin>
    

2. Shadowing Jackson and Jakarta Validation

  • We packaged Jackson and Jakarta Validation directly into our app, effectively shadowing the versions provided by Confluence:

    <dependencies>
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>7.0.5.Final</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.17.2</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.17.2</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.17.2</version>
        </dependency>
        <dependency>
            <groupId>jakarta.validation</groupId>
            <artifactId>jakarta.validation-api</artifactId>
            <version>3.0.2</version>
        </dependency>
    </dependencies>
    
  • Additionally, we had to explicitly list Jakarta and Jackson dependencies as exceptions in our confluence-maven-plugin configuration to bypass the packaging restrictions:

    <plugin>
        <groupId>com.atlassian.maven.plugins</groupId>
        <artifactId>confluence-maven-plugin</artifactId>
        <version>9.0.2</version>
        <extensions>true</extensions>
        <configuration>
            [...]
            <banningExcludes>
                <exclude>com.fasterxml.jackson.core:jackson-core</exclude>
                <exclude>com.fasterxml.jackson.core:jackson-databind</exclude>
                <exclude>com.fasterxml.jackson.core:jackson-annotations</exclude>
                <exclude>jakarta.validation:jakarta.validation-api</exclude>
            </banningExcludes>
            [...]
        </configuration>
    </plugin>
    

3. Validation Handling

  • We created helper beans to handle validation and authorization. Instead of using annotations like @Valid, validation is now handled through a dedicated Validator class:
import lombok.Getter;

import java.io.Serializable;
import java.util.List;

public class ValidatorException extends Exception {
    @Getter private final List<String> errors;
    @Getter private final Serializable entity;

    public ValidatorException(List<String> errors, Serializable entity) {
        super("validation failed");
        this.entity = entity;
        this.errors = errors;
    }
}

import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.ValidatorFactory;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Set;

import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;


@Provider
public class ValidatorExceptionHandler implements ExceptionMapper<ValidatorException> {
    @Override
    public Response toResponse(ValidatorException e){
        String message = "Validation failed";

        return Response
            .status(400)
            .entity(HttpError.builder()
                .statusCode(400)
                .message(message)
                .errors(e.getErrors())
                .build()
            ).build();
    }
}

public class Validator {
    public void validate(Serializable entity) throws ValidatorException {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        jakarta.validation.Validator validator = factory.getValidator();
        Set<ConstraintViolation<Object>> violations = validator.validate(entity);

        if (!violations.isEmpty()) {
            ArrayList<String> messages = new ArrayList<>();
            for (ConstraintViolation<Object> violation: violations) {
                messages.add(violation.getMessage());
            }

            throw new ValidatorException(messages, entity);
        }
    }
}

4. Authorization Handling

  • Similarly, we implemented explicit checks for authorization. The AdminChecker bean allows us to check permissions manually, replacing @AdminOnly:
public class AuthenticationRequiredException extends SecurityException {
   public AuthenticationRequiredException() {
       super("Client must be authenticated to access this resource.");
   }
}

import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import java.util.Collections;

@Provider
public class AuthenticationRequiredExceptionHandler implements ExceptionMapper<AuthenticationRequiredException> {
   @Override
   public Response toResponse(AuthenticationRequiredException e){
       return Response
           .status(401)
           .entity(HttpError.builder()
               .statusCode(401)
               .message(e.getMessage())
               .errors(Collections.singletonList("Authentication required"))
               .build()
           ).build();
   }
}

public class AuthorisationException extends SecurityException {
   public AuthorisationException(String message) {
       super(message);
   }
}

import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import java.util.Collections;

@Provider
public class AuthorisationExceptionHandler implements ExceptionMapper<AuthorisationException> {
   @Override
   public Response toResponse(AuthorisationException e){
       return Response
           .status(403)
           .entity(HttpError.builder()
               .statusCode(403)
               .message(e.getMessage())
               .errors(Collections.singletonList("Authorisation required"))
               .build()
           ).build();
   }
}

import com.atlassian.user.User;
import com.atlassian.confluence.security.Permission;
import com.atlassian.confluence.security.PermissionManager;
import com.atlassian.confluence.user.AuthenticatedUserThreadLocal;
import com.atlassian.confluence.user.ConfluenceUser;
import com.atlassian.confluence.user.UserAccessor;


public class AdminChecker {
   private final UserAccessor userAccessor;
   private final PermissionManager permissionManager;


   public AdminChecker(UserAccessor userAccessor, PermissionManager permissionManager) {
       this.userAccessor = userAccessor;
       this.permissionManager = permissionManager;
   }


   public void check() {
       ConfluenceUser user = AuthenticatedUserThreadLocal.get();
       if (user == null) {
           throw new AuthenticationRequiredException();
       }

       if (!isAdmin(user)) {
           throw new AuthorisationException("You must be a system administrator to access this resource.");
       }
   }

   private boolean isAdmin(ConfluenceUser user) {
       // Check user has system admin permission.
       // We have to cast ConfluenceUser to User here to access the old method that is available in Confluence 7/8.
       return permissionManager.hasPermission((User)user, Permission.ADMINISTER, PermissionManager.TARGET_SYSTEM);
   }
}

5. Updated REST Resource

  • Our REST resources have been updated to perform explicit serialization, validation, and permission checks:

    import com.fasterxml.jackson.core.JacksonException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.springframework.stereotype.Component;
    
    import javax.inject.Inject;
    
    import javax.ws.rs.Consumes;
    import javax.ws.rs.PUT;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.core.Response;
    import java.io.IOException;
    import java.io.InputStream;
    
    @Path("/configuration")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public class ConfigurationRest {
        private final Validator validator;
        private final AdminChecker adminChecker;
    
        @Inject
        public ConfigurationRest(Validator validator, AdminChecker adminChecker) {
            this.validator = validator;
            this.adminChecker = adminChecker;
        }
    
        @PUT
        @Produces(MediaType.APPLICATION_JSON)
        @Consumes(MediaType.APPLICATION_JSON)
        public Response putConfiguration(InputStream requestBody) throws ValidatorException, JacksonException, IOException {
            adminChecker.check(); // Explicit permission check
    
            // Explicit deserialization
            ObjectMapper mapper = new ObjectMapper();
            Configuration configuration = mapper.readValue(requestBody, Configuration.class);
    
            // Explicit validation
            validator.validate(configuration);
    
            // Explicit serialization
            byte[] data = new ObjectMapper().writeValueAsBytes(configuration);
            return Response.ok(data).build();
        }
    }
    

I realize we are quite late to the party but maybe this helps somebody else.

The changes we made have made our code more verbose but also more predictable and portable, especially across major platform versions. We believe the trade-off of replacing implicit behavior with explicit code will pay off in the long run, particularly in terms of maintainability and debugging. As it is robust against changing versions of libraries and renaming of packages.


Update

We encountered an edge case issue with hibernate-validator and jakarta-validation, so we decided to use Apache BVal as an alternative. We chose BVal 2.x because it is still compatible with JDK 8, which is the minum requirement for Confluence 7, while the 3.x version requires JDK 11. BVal 2.x continues to use javax.validation, which fits our needs without significant code changes.

To implement this, replace all imports of jakarta.validation.* with javax.validation.* and change the dependencies for hibernate-validator and jakarta-validation to:

<dependency>
    <groupId>org.apache.bval</groupId>
    <artifactId>bval-jsr</artifactId>
    <version>2.0.6</version>
</dependency>
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
</dependency>

Or keep using jakarta-validation with BVal 3.x if you don’t need to be compatible with JDK 8.

I would recommend using BVal over hibernate-validation as it is much simpler and build for simple bean validation and therefore much less likely to cause issues.

3 Likes

For $webResourceManager.requireResource(), have you tried #requireResource("pluginKey:moduleKey") ?

For WRM (the webpack plugin), we’ve migrated successfully, but we’ve tried to keep our providedDependencies.json as empty as possible because it didn’t work. Here’s ours:

const mappings = new Map();
mappings.set('deps/aui_progress_indicator', {
    dependency: 'com.atlassian.auiplugin:aui-progress-indicator',
    import: {},
});

mappings.set('deps/aui_select2', {
    dependency: 'com.atlassian.auiplugin:aui-select2',
    import: {},
});

mappings.set('deps/aui_select', {
    dependency: 'com.atlassian.auiplugin:aui-select',
    import: {},
});

mappings.set('deps/aui_inline_dialog2', {
    dependency: 'com.atlassian.auiplugin:aui-inline-dialog2',
    import: {},
});

module.exports = mappings;

But when we actually need a resource in our files, we do:

import 'wr-dependency!com.atlassian.auiplugin:aui-select';
import 'wr-dependency!com.atlassian.auiplugin:aui-dialog2';

which is more reliable than the providedDependencies.json thing, which doesn’t work.

1 Like

Hi,

We are using confluence-flyingpdf-plugin source code as a separate module in our plugin before Confluence 9. Now, during the transition to confluence 9.0.1, we managed to adopt our plugin codes to platform 7 with several changes successfully, but we have some errors related to confluence pdf export plugin source codes like below.

Caused by: java.lang.ClassNotFoundException: org.cyberneko.html.HTMLConfiguration not found by tr.com.obss.plugin.confluence-baseline-plugin [299]
	at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1591)
	at org.apache.felix.framework.BundleWiringImpl.access$300(BundleWiringImpl.java:79)
	at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1976)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
Caused by: java.lang.NoClassDefFoundError: com/atlassian/plugin/webresource/CssWebResource
	at tr.com.obss.plugin.extra.flyingpdf.PdfResourceManager.<clinit>(PdfResourceManager.java:13)
	at tr.com.obss.plugin.config.PluginConfiguration.pdfResourceManager(PluginConfiguration.java:335)
	at tr.com.obss.plugin.config.PluginConfiguration$$EnhancerBySpringCGLIB$$e1e8b855.CGLIB$pdfResourceManager$8(<generated>)
	at tr.com.obss.plugin.config.PluginConfiguration$$EnhancerBySpringCGLIB$$e1e8b855$$FastClassBySpringCGLIB$$b1c8f03a.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
	at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331)
	at tr.com.obss.plugin.config.PluginConfiguration$$EnhancerBySpringCGLIB$$e1e8b855.pdfResourceManager(<generated>)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:569)
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
	... 44 more
Caused by: java.lang.NoClassDefFoundError: com/atlassian/confluence/importexport/impl/ExportFileNameGenerator
	at java.base/java.lang.Class.getDeclaredMethods0(Native Method)
	at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3402)
	at java.base/java.lang.Class.getDeclaredMethods(Class.java:2504)
	at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:467)

The below one is our import-package configuration.

						<Import-Package>
							com.atlassian.plugins.*;resolution:=optional,
							com.apple.*;resolution:=optional,
							com.atlassian.config.util;resolution:=optional,
							com.atlassian.json.jsonorg.*;resolution:=optional,
							com.google.common.*;resolution:=optional,
							com.lowagie.toolbox;resolution:=optional,
							com.opensymphony.webwork.*;resolution:=optional,
							org.apache.batik.transcoder.*;resolution:=optional,
							org.apache.commons.*;resolution:=optional,
							org.apache.xerces.*;resolution:=optional,
							org.bouncycastle.*;resolution:=optional,
							org.codehaus.jackson.*;resolution:=optional,
							org.cyberneko.html.*;resolution:=optional,
							org.jsoup.*;resolution:=optional,
							bsh.*;resolution:=optional,
							com.jamonapi.*;resolution:=optional,
							groovy.*;resolution:=optional,
							io.netty.*;resolution:=optional,
							io.reactivex.*;resolution:=optional,
							org.springframework.cglib.core;resolution:=optional,
							org.springframework.cglib.proxy;resolution:=optional,
							org.springframework.cglib.reflect;resolution:=optional,
							javax.*;resolution:=optional,
							org.springframework.osgi.*;resolution:="optional",
							org.eclipse.gemini.blueprint.service;version="[2.0.0,3.0.4)";resolution:=optional,
							org.eclipse.gemini.blueprint.service.exporter.support.*;resolution:=optional,
							com.atlassian.confluence.api.service.accessmode.*;resolution:=optional,
							com.atlassian.confluence.importexport.impl.*;resolution:=optional
						</Import-Package>

Looks like some of the packages used in pdf export module are not being exported via OSGI in Confluence 9.

If we try to add some of them as compile scope dependencies, we face some classloader issues, probably due to incompatibilities between libraries and OSGI bundle requirements.

Is it possible to use the packages in some way that OSGI does not find in runtime? Or is there any alternative way to use pdf-export-plugin source code with platform 7?

Kind regards

Hi @AliUstun,
I think I had an issue with the same package, but another class. However, maybe this will fix your problem as well.

I had to compile the net.sourceforge.nekohtml.nekohtml package.

        <dependency>
            <groupId>net.sourceforge.nekohtml</groupId>
            <artifactId>nekohtml</artifactId>
            <version>1.9.22-atlassian-5</version>
            <scope>compile</scope>
        </dependency>

Cheers,
Marcel

Hi @m.frank

When I try to add this, I get some classLoader errors in runtime like the one below.

ava.lang.LinkageError: loader constraint violation: when resolving method 'void org.apache.xerces.parsers.DOMParser.parse(org.xml.sax.InputSource)' the class loader org.apache.felix.framework.BundleWiringImpl$BundleClassLoader @4c5e5d1 of the current class, tr/com/obss/plugin/extra/flyingpdf/html/HtmlToDomParser, and the class loader org.apache.catalina.loader.ParallelWebappClassLoader @75c003bd for the method's defining class, org/apache/xerces/parsers/DOMParser, have different Class objects for the type org/xml/sax/InputSource used in the signature (tr.com.obss.plugin.extra.flyingpdf.html.HtmlToDomParser is in unnamed module of loader org.apache.felix.framework.BundleWiringImpl$BundleClassLoader @4c5e5d1, parent loader org.apache.catalina.loader.ParallelWebappClassLoader @75c003bd; org.apache.xerces.parsers.DOMParser is in unnamed module of loader org.apache.catalina.loader.ParallelWebappClassLoader @75c003bd, parent loader java.net.URLClassLoader @6576fe71)

But I think our main issue here is that some of the required packages for us are not being exported to plugins in the OSGI context.

filterMatches Package com.atlassian.confluence.importexport.impl is internal and is not available for export to plugin
filterMatches Package org.apache.xerces.parsers is internal and is not available for export to plugin 

I am not sure if all of the missing packages can be found in a specific jar, and work compatible like those added from OSGI. I think the situation here may be addressed better if there is any possible way to use these packages like before platform 7.

Hey @AliUstun,
ah yeah, I think I had to add more dependencies to make the nekohtml run:

        <dependency>
            <groupId>xml-resolver</groupId>
            <artifactId>xml-resolver</artifactId>
            <version>1.2</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>xerces</groupId>
            <artifactId>xercesImpl</artifactId>
            <version>2.12.2</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>net.sourceforge.nekohtml</groupId>
            <artifactId>nekohtml</artifactId>
            <version>1.9.22-atlassian-5</version>
            <scope>compile</scope>
        </dependency>

I think it tries to access the xerces dependency from the nekohtml, but as it’s internal, it cannot access it from atlassian. So you could compile it on your own.

Tbh. I do not really like to add multiple dependencies to make the nekohtml work, but I did not find another way.

Cheers,
Marcel

I am getting the following error in Confluence 9.0.3. The app has confluence-create-content-plugin as dependency for the blueprints. Also the app didn’t have any active object entities configured in it, and I didn’t configure module in the plugin descriptor.

plugin [{com.my.plugin}] invoking ActiveObjects before configuration module is enabled or plugin is missing an configuration module. Note that scanning of entities from the ao.model package is no longer supported.

Hi everyone,

I’m having trouble converting my user profile page. I’ve transitioned it to a Soy template and added the following decorator:

<head>
    <meta name="decorator" content="atl.userprofile"/>
</head>

While this setup does render the page, it takes over the entire page rather than just the section beneath the profile tabs. Has anyone else experienced this, and is there a way to fix it?

Cheers,
William

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.