gitblit icon indicating copy to clipboard operation
gitblit copied to clipboard

Init failure on Gerrit plugin

Open orgads opened this issue 3 years ago • 19 comments

I'm trying to revive the gitblit plugin for Gerrit 3.5. I built it successfully, but when I'm trying to load it, I get the following exception:

com.google.gerrit.server.plugins.PluginInstallException: Unable to provision, see the following errors:

1) [Guice/ErrorInjectingConstructor]: NoClassDefFoundError: javax/activation/DataSource
  at NotificationManager.<init>(NotificationManager.java:55)
  at NotificationManager.class(NotificationManager.java:43)
  while locating NotificationManager
  at GitblitManager.<init>(GitblitManager.java:151)
      \_ for 5th parameter
  at GitblitManager.class(GitblitManager.java:108)
  while locating GitblitManager
  at GerritAuthFilter.<init>(GerritAuthFilter.java:43)
      \_ for 1st parameter gitBlit
  at GerritAuthFilter.class(GerritAuthFilter.java:43)
  at GerritWicketFilter.<init>(GerritWicketFilter.java:72)
      \_ for 2nd parameter gerritAuthFilter
  at GerritWicketFilter.class(GerritWicketFilter.java:49)
  while locating GerritWicketFilter

Learn more:
  https://github.com/google/guice/wiki/ERROR_INJECTING_CONSTRUCTOR

1 error

======================
Full classname legend:
======================
GerritAuthFilter:     "com.googlesource.gerrit.plugins.gitblit.auth.GerritAuthFilter"
GerritWicketFilter:   "com.googlesource.gerrit.plugins.gitblit.GerritWicketFilter"
GitblitManager:       "com.gitblit.manager.GitblitManager"
NotificationManager:  "com.gitblit.manager.NotificationManager"
========================
End of classname legend:
========================

I tried replacing NotificationManager contents with NoopNotificationManager, and it worked, so I guess it's something in the class implementation.

orgads avatar Mar 17 '22 18:03 orgads

What Java version is this running on? This sounds like a problem that comes up with moving to Java 9 or higher. From Java 9 on some classes were not part of the JVE anymore and need to be included as an explicit dependency. That is why the dependency to com.sun.activation:javax.activation:1.2.0 was added. You may have to make sure that is present in your build.

flaix avatar Mar 18 '22 12:03 flaix

Java 11. I have this dependency.

orgads avatar Mar 18 '22 12:03 orgads

ping?

orgads avatar Apr 04 '22 19:04 orgads

I would love to help, but I don't build the plugin or run a Gerrit instance. So I don't know how else to help. From experience and from the error message, it is a missing dependency that is not present in your server's runtime class path. I cannot think of anything else but to make sure that the java.activation JAR is preset in the class path that is used for the server.

flaix avatar Apr 07 '22 09:04 flaix

Were you able to get more debug information or other information? Like check if the JAR is present at runtime?

flaix avatar Apr 27 '22 10:04 flaix

I have a simple way to reproduce, if it helps. This is a jar I built with the change linked above, and latest gerrit 3.5: gitblit.zip.

Rename it to jar, then run:

docker run --rm -ti -p 8080:8080 -p 29418:29418 -v $PWD/gitblit.jar:/var/gerrit/plugins/gitblit.jar gerritcodereview/gerrit:3.5.1

This is the output I'm getting:

[2022-04-27T15:15:09.916Z] [main] WARN  com.googlesource.gerrit.plugins.replication.DestinationConfigParser : Replication config does not exist or it's empty; not replicating
[2022-04-27T15:15:09.936Z] [main] INFO  com.google.gerrit.server.plugins.PluginLoader : Loaded plugin replication, version v3.5.1
[2022-04-27T15:15:09.987Z] [main] INFO  com.google.gerrit.server.plugins.PluginLoader : Loaded plugin reviewnotes, version v3.5.1
[2022-04-27T15:15:10.009Z] [main] INFO  com.google.gerrit.server.plugins.PluginLoader : Loaded plugin singleusergroup, version v3.5.1
[2022-04-27T15:15:10.112Z] [main] INFO  com.google.gerrit.server.plugins.PluginLoader : Loaded plugin uploadvalidator, version v3.0.0-rc1-284-gefecf8cdf4
[2022-04-27T15:15:10.167Z] [main] INFO  com.google.gerrit.server.plugins.PluginLoader : Loaded plugin webhooks, version v3.5.1
[2022-04-27T15:15:10.177Z] [main] INFO  com.google.gerrit.server.config.ScheduleConfig : No schedule configuration for "accountDeactivation".
[2022-04-27T15:15:10.189Z] [WorkQueue-2[java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask@475bf443[Not completed, task = java.util.concurrent.Executors$RunnableAdapter@4da39f33[Wrapped task = com.google.gerrit.server.logging.LoggingContextAwareRunnable@436478f7]]]] INFO  com.googlesource.gerrit.plugins.deleteproject.fs.RepositoryCleanupTask : Cleaning up expired git repositories...
[2022-04-27T15:15:10.198Z] [WorkQueue-2[java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask@475bf443[Not completed, task = java.util.concurrent.Executors$RunnableAdapter@4da39f33[Wrapped task = com.google.gerrit.server.logging.LoggingContextAwareRunnable@436478f7]]]] INFO  com.googlesource.gerrit.plugins.deleteproject.fs.RepositoryCleanupTask : Cleaning up expired git repositories... Done
[2022-04-27T15:15:10.209Z] [main] INFO  com.google.gerrit.sshd.SshDaemon : Started Gerrit APACHE-SSHD-2.6.0 on *:29418
[2022-04-27T15:15:10.212Z] [main] INFO  org.eclipse.jetty.server.Server : jetty-9.4.36.v20210114; built: 2021-01-14T16:44:28.689Z; git: 238ec6997c7806b055319a6d11f8ae7564adc0de; jvm 11.0.14.1+1-LTS
[2022-04-27T15:15:10.245Z] [main] INFO  org.eclipse.jetty.server.session : DefaultSessionIdManager workerName=node0
[2022-04-27T15:15:10.246Z] [main] INFO  org.eclipse.jetty.server.session : No SessionScavenger set, using defaults
[2022-04-27T15:15:10.247Z] [main] INFO  org.eclipse.jetty.server.session : node0 Scavenging every 660000ms
[2022-04-27T15:15:10.451Z] [main] INFO  org.eclipse.jetty.server.session : node0 Stopped scavenging
[2022-04-27T15:15:10.453Z] [main] ERROR com.google.gerrit.pgm.Daemon : Unable to start daemon
java.lang.IllegalStateException: Cannot start HTTP daemon
        at com.google.gerrit.pgm.http.jetty.JettyServer$Lifecycle.start(JettyServer.java:109)
        at com.google.gerrit.lifecycle.LifecycleManager.start(LifecycleManager.java:95)
        at com.google.gerrit.pgm.Daemon.start(Daemon.java:386)
        at com.google.gerrit.pgm.Daemon.run(Daemon.java:285)
        at com.google.gerrit.pgm.util.AbstractProgram.main(AbstractProgram.java:61)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at com.google.gerrit.launcher.GerritLauncher.invokeProgram(GerritLauncher.java:224)
        at com.google.gerrit.launcher.GerritLauncher.mainImpl(GerritLauncher.java:120)
        at com.google.gerrit.launcher.GerritLauncher.main(GerritLauncher.java:65)
        at Main.main(Main.java:28)
Caused by: com.google.inject.ProvisionException: Unable to provision, see the following errors:

1) [Guice/ErrorInjectingConstructor]: NoClassDefFoundError: javax/activation/DataSource
  at NotificationManager.<init>(NotificationManager.java:55)
  at NotificationManager.class(NotificationManager.java:43)
  while locating NotificationManager
  at GitblitManager.<init>(GitblitManager.java:151)
      \_ for 5th parameter
  at GitblitManager.class(GitblitManager.java:108)
  while locating GitblitManager
  at GerritAuthFilter.<init>(GerritAuthFilter.java:43)
      \_ for 1st parameter gitBlit
  at GerritAuthFilter.class(GerritAuthFilter.java:43)
  at GerritWicketFilter.<init>(GerritWicketFilter.java:72)
      \_ for 2nd parameter gerritAuthFilter
  at GerritWicketFilter.class(GerritWicketFilter.java:49)
  while locating GerritWicketFilter

Learn more:
  https://github.com/google/guice/wiki/ERROR_INJECTING_CONSTRUCTOR

1 error

======================
Full classname legend:
======================
GerritAuthFilter:     "com.googlesource.gerrit.plugins.gitblit.auth.GerritAuthFilter"
GerritWicketFilter:   "com.googlesource.gerrit.plugins.gitblit.GerritWicketFilter"
GitblitManager:       "com.gitblit.manager.GitblitManager"
NotificationManager:  "com.gitblit.manager.NotificationManager"
========================
End of classname legend:
========================

orgads avatar Apr 27 '22 15:04 orgads

How did you manage to build it? I tried to build the plugin, but it complains about downloading wicket-extensions from maven central. I cannot download the zip file you attached, so I tried to build it myself. What changed so that it can be built from the stock JAR, compared to previously?

Edit: Apparently it just needs to be executed a few times to correct itself. But now I am stuck at the build complaining about jgit

ERROR: /Users/florian/Devel/Tests/Gerrit/gerrit/WORKSPACE:107:17: fetching local_repository rule //external:jgit: java.io.IOException: No WORKSPACE file found in /private/var/tmp/_bazel_florian/992c15ad0c448f20077c9f60735f3ed5/external/jgit
ERROR: /Users/florian/Devel/Tests/Gerrit/gerrit/lib/BUILD:59:13: //lib:jgit-archive depends on @jgit//org.eclipse.jgit.archive:jgit-archive in repository @jgit which failed to fetch. no such package '@jgit//org.eclipse.jgit.archive': No WORKSPACE file found in /private/var/tmp/_bazel_florian/992c15ad0c448f20077c9f60735f3ed5/external/jgit
ERROR: Analysis of target '//plugins/gitblit:gitblit' failed; build aborted:

flaix avatar Nov 19 '22 12:11 flaix

Do you have all the submodules checked out? Run git submodule update --init and retry building.

orgads avatar Nov 19 '22 16:11 orgads

I take you build this on Linux? Because I am getting nowhere with macOS.

flaix avatar Nov 19 '22 18:11 flaix

Well, as expected the resulting gitblit.jar plugin does not contain the javax.activation classes. You said you have this dependency? I got your branch but did not find it in the external_plugin_deps.bzl file.

Anyhow, if I add below patch, it builds and runs in Gerrit. Well, it starts. I have no idea how to see if it actually works then. You may want to apply the patch and try it in Gerrit.

diff --git a/BUILD b/BUILD
index 2593ebd..91d3db3 100644
--- a/BUILD
+++ b/BUILD
@@ -22,6 +22,7 @@ gerrit_plugin(
         "@groovy//jar",
         "@httpcore//jar:neverlink",
         "@ivy//jar",
+        "@javax-activation//jar",
         "@jdom//jar",
         "@libpam4j//jar",
         "@lucene-core//jar:neverlink",
diff --git a/external_plugin_deps.bzl b/external_plugin_deps.bzl
index cc73bca..86800b8 100644
--- a/external_plugin_deps.bzl
+++ b/external_plugin_deps.bzl
@@ -106,6 +106,12 @@ def external_plugin_deps():
     sha1 = '08210b4af6f055ada934753facd27d7abf9d01a8',
   )

+  maven_jar(
+    name = 'javax-activation',
+    artifact = 'com.sun.activation:javax.activation:1.2.0',
+    sha1 = 'bf744c1e2776ed1de3c55c8dac1057ec331ef744',
+  )
+
   maven_jar(
     name = 'ivy',
     artifact = 'org.apache.ivy:ivy:2.2.0',

flaix avatar Nov 19 '22 19:11 flaix

While we are at it, is there a way for Gitblit to know that it runs as a Gerrit plugin?

flaix avatar Nov 20 '22 13:11 flaix

@flaix Thanks for the hint. Looks better, but it now fails with another error:

[2022-11-20T15:20:07.406+02:00] [HTTP GET /review/plugins/gitblit/repositories/ (orgads from 10.1.2.3)] ERROR org.apache.wicket.RequestCycle : Can't instantiate page using constructor public com.gitblit.wicket.pages.RepositoriesPage()
org.apache.wicket.WicketRuntimeException: Can't instantiate page using constructor public com.gitblit.wicket.pages.RepositoriesPage()
	at org.apache.wicket.session.DefaultPageFactory.createPage(DefaultPageFactory.java:212)
	at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:57)
	at org.apache.wicket.request.target.component.BookmarkablePageRequestTarget.newPage(BookmarkablePageRequestTarget.java:298)
	at org.apache.wicket.request.target.component.BookmarkablePageRequestTarget.getPage(BookmarkablePageRequestTarget.java:320)
	at org.apache.wicket.request.target.component.BookmarkablePageRequestTarget.processEvents(BookmarkablePageRequestTarget.java:234)
	at org.apache.wicket.request.AbstractRequestCycleProcessor.processEvents(AbstractRequestCycleProcessor.java:92)
	at org.apache.wicket.RequestCycle.processEventsAndRespond(RequestCycle.java:1279)
	at org.apache.wicket.RequestCycle.step(RequestCycle.java:1358)
	at org.apache.wicket.RequestCycle.steps(RequestCycle.java:1465)
	at org.apache.wicket.RequestCycle.request(RequestCycle.java:545)
	at org.apache.wicket.protocol.http.WicketFilter.doGet(WicketFilter.java:486)
	at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:319)
	at com.googlesource.gerrit.plugins.gitblit.GerritWicketFilter.doFilter(GerritWicketFilter.java:128)
	at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:82)
	at com.google.inject.servlet.ManagedFilterPipeline.dispatch(ManagedFilterPipeline.java:121)
	at com.google.inject.servlet.GuiceFilter.doFilter(GuiceFilter.java:133)
	at com.google.gerrit.httpd.plugins.HttpPluginServlet.service(HttpPluginServlet.java:229)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
	at com.google.inject.servlet.ServletDefinition.doServiceImpl(ServletDefinition.java:290)
	at com.google.inject.servlet.ServletDefinition.doService(ServletDefinition.java:280)
	at com.google.inject.servlet.ServletDefinition.service(ServletDefinition.java:184)
	at com.google.inject.servlet.ManagedServletPipeline.service(ManagedServletPipeline.java:89)
	at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:85)
	at com.google.gerrit.httpd.raw.StaticModule$PolyGerritFilter.doFilter(StaticModule.java:408)
	at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:82)
	at com.google.gerrit.httpd.GetUserFilter.doFilter(GetUserFilter.java:92)
	at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:82)
	at com.google.gerrit.httpd.RequireSslFilter.doFilter(RequireSslFilter.java:72)
	at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:82)
	at com.google.gerrit.httpd.RunAsFilter.doFilter(RunAsFilter.java:120)
	at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:82)
	at com.google.gerrit.httpd.SetThreadNameFilter.doFilter(SetThreadNameFilter.java:62)
	at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:82)
	at com.google.gerrit.httpd.AllRequestFilter$FilterProxy$1.doFilter(AllRequestFilter.java:139)
	at com.google.gerrit.httpd.AllowRenderInFrameFilter.doFilter(AllowRenderInFrameFilter.java:56)
	at com.google.gerrit.httpd.AllRequestFilter$FilterProxy$1.doFilter(AllRequestFilter.java:135)
	at com.google.gerrit.httpd.AllRequestFilter$FilterProxy.doFilter(AllRequestFilter.java:141)
	at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:82)
	at com.google.gerrit.httpd.RequestCleanupFilter.doFilter(RequestCleanupFilter.java:60)
	at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:82)
	at com.google.gerrit.httpd.RequestMetricsFilter.doFilter(RequestMetricsFilter.java:92)
	at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:82)
	at com.google.gerrit.httpd.RequestContextFilter.doFilter(RequestContextFilter.java:64)
	at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:82)
	at com.google.inject.servlet.ManagedFilterPipeline.dispatch(ManagedFilterPipeline.java:121)
	at com.google.inject.servlet.GuiceFilter.doFilter(GuiceFilter.java:133)
	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:548)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1435)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:501)
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1350)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
	at org.eclipse.jetty.server.Server.handle(Server.java:516)
	at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:388)
	at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:633)
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:380)
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:273)
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
	at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:773)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:905)
	at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
	at org.apache.wicket.session.DefaultPageFactory.createPage(DefaultPageFactory.java:192)
	... 70 more
Caused by: java.lang.ClassCastException: class com.gitblit.wicket.GitBlitWebSession cannot be cast to class org.apache.wicket.Session (com.gitblit.wicket.GitBlitWebSession is in unnamed module of loader java.net.FactoryURLClassLoader @6901f5fd; org.apache.wicket.Session is in unnamed module of loader java.net.FactoryURLClassLoader @67d3610b)
	at org.apache.wicket.protocol.http.AbstractHttpSessionStore.lookup(AbstractHttpSessionStore.java:245)
	at org.apache.wicket.Session.findOrCreate(Session.java:226)
	at org.apache.wicket.Session.findOrCreate(Session.java:214)
	at org.apache.wicket.Session.get(Session.java:253)
	at org.apache.wicket.Application$1.onInstantiation(Application.java:299)
	at org.apache.wicket.Application.notifyComponentInstantiationListeners(Application.java:1093)
	at org.apache.wicket.Component.<init>(Component.java:926)

orgads avatar Nov 20 '22 13:11 orgads

I take you build this on Linux? Because I am getting nowhere with macOS.

In order to build, you need to replace external_plugin_deps.bzl in plugins with the one in gitblit. It's in the README.

cd plugins
ln -sf gitblit/external_plugin_deps.bzl .
cd ..
bazel build plugins/gitblit

orgads avatar Nov 20 '22 13:11 orgads

In order to build, you need to replace external_plugin_deps.bzl in plugins with the one in gitblit. It's in the README.

Yeah, I did that according to the Readme, but I could not get it compiled on macOS. The build didn't like the clang C compiler. So I switched to a Linux VM.

flaix avatar Nov 20 '22 16:11 flaix

I guess now come the hard problems as we have reached the realms of class loaders.

How can one put some repositories in the container to see that?

flaix avatar Nov 20 '22 16:11 flaix

Here is a new build for 3.7: gitblit.zip

Rename gitblit.war, use this docker-compose.yml and run docker-compose up:

version: '3'

services:
  gerrit:
    image: gerritcodereview/gerrit:3.7.0
    ports:
      - "8070:8080"
    volumes:
      - ./gitblit.jar:/var/gerrit/plugins/gitblit.jar
      - gerrit-etc:/var/gerrit/etc
      - gerrit-git:/var/gerrit/git
      - gerrit-db:/var/gerrit/db
      - gerrit-index:/var/gerrit/index
      - gerrit-cache:/var/gerrit/cache
    environment:
      - CANONICAL_WEB_URL=http://localhost:8070

volumes:
  gerrit-etc:
  gerrit-git:
  gerrit-db:
  gerrit-index:
  gerrit-cache:

There are 2 repositories that are created automatically, All-Projects and All-Users.

You can reproduce the issue just by opening http://your-server:8080/plugins/gitblit/repositories/

I pushed my latest changes here: https://github.com/orgads/gerrit-gitblit-plugin, on branch master.

Switched back to building gitblit from source, and using MAVEN_LOCAL.

orgads avatar Nov 20 '22 17:11 orgads

I have to say I'm really confused about https://github.com/orgads/gerrit-gitblit-plugin/commit/d0357a6e15267a687f791149d0d94539fbf56cdb#diff-7065071696a179130d4c9022da41d3b5ca979899627876119e6c88e2573a6a25R140. How come 2 calls to the same function (getAttribute) return different types? The first call for gerrit-username returns Optional<String>, but the second call for gerrit-token returns String. If I change the casts, I get an error (cannot cast Optional to String, or String to Optional). And it's not even consistent. On my system, both return String.

orgads avatar Nov 20 '22 19:11 orgads

@lucamilanesio @paladox @davido Maybe you'll have ideas regarding https://github.com/gitblit/gitblit/issues/1413#issuecomment-1321131828?

orgads avatar Nov 21 '22 06:11 orgads

When I run with your docker compose file, I don't get the error about class loaders you pasted. But I do get the class cast exception. This seems something in the plugin, I am guessing. It might depend on where the attributes were set. I don't know if that happens in Gerrit or the plugin. The getAttribute method returns an Object, since any type can be attached to the session as an Object. So type safe handling would probably be to check for the type with an instanceof and act accordingly. But I don't really know about how Gerrit works there.

flaix avatar Nov 21 '22 21:11 flaix