Skip to content

refactor: remove jackson dependency - #101

Merged
paodb merged 4 commits into
masterfrom
refactor-100
Aug 13, 2026
Merged

refactor: remove jackson dependency#101
paodb merged 4 commits into
masterfrom
refactor-100

Conversation

@javier-godoy

@javier-godoy javier-godoy commented Aug 12, 2026

Copy link
Copy Markdown
Member

Close #100

The problem is structural, not a stale version

The v25 build fails at prepare-frontend with NoClassDefFoundError: com/fasterxml/jackson/annotation/JsonSerializeAs. Diffing the effective POM for 25.2.6 against 25.3-SNAPSHOT shows why: Vaadin's BOM manages ~130 com.fasterxml.jackson.* artifacts in 25.2.6 and none in 25.3-SNAPSHOT.

While the BOM was managing those versions, our own pin was being silently overridden and we never noticed it existed. Once that management disappeared, our jackson-databind:2.13.4.2 — a 2023 Dependabot security bump, chosen for Vaadin 14 — became authoritative and pulled jackson-annotations:2.13.4 onto the classpath. Flow 25.3 runs on Jackson 3, whose JacksonAnnotationIntrospector requires jackson-annotations ≥ 2.21. Maven's nearest-wins mediation is explicit about the collision:

tools.jackson.core:jackson-databind:jar:3.1.5:compile
- (com.fasterxml.jackson.core:jackson-annotations:jar:2.21 - omitted for conflict with 2.13.4)

So the add-on had a latent, invisible dependency on Vaadin continuing to manage a transitive artifact on our behalf. That's the actual defect. The NoClassDefFoundError is a symptom.

Why not just bump the pin

I tried this first: 2.13.4.2 → 2.22.1 turns all four profiles green today. I'm not proposing it, because it only works by coincidence of alignment.

jackson-annotations is the one artifact Jackson 2 and Jackson 3 still share — it stayed under com.fasterxml.jackson.core when core/databind moved to tools.jackson.*. Pinning it means pinning a shared artifact whose floor is set by Vaadin's internals and rises with Flow releases. We'd re-break on some future 25.x, discover it only at prepare-frontend on a snapshot profile, and repeat this investigation. We'd also be exporting a hard Jackson pin to every downstream consumer of the add-on.

Why not migrate to Jackson 3

Not available to us. tools.jackson.core:jackson-databind:3.1.5 is compiled to class file major version 61 — Java 17 (checked against the jar's bytecode header). This add-on builds one source tree against four baselines: v14→Java 8, v23→11, v24→17, v25→21. An import of tools.jackson.databind.ObjectMapper compiles fine under -source 8 and then throws UnsupportedClassVersionError the first time a v14 or v23 user renders a chart. Supporting both would mean profile-specific source sets for a single serialization method.

Why elemental.json

We used Jackson for exactly one thing: turning OrgChartItem into a JSON string for the client widget. That's ~30 lines of explicit construction, and it buys:

  • No new dependency — one fewer. elemental.json is already on the classpath on every profile we support (either natively in flow-server or transitively via json-migration-helper).
  • No version surface at all. No groupId migration, no JDK floor above ours, no BOM to depend on.
  • It's the type Flow's executeJs already speaks. That unlocked a real simplification rather than a lateral move: state now crosses as a JsonValue instead of a string the client had to $.parseJSON, removing an encode/decode round-trip and one more place to get escaping wrong.

Summary by CodeRabbit

  • Improvements

    • Improved organizational chart data handling, including nested items, custom data, titles, and hybrid nodes.
    • Updated chart state processing for more consistent server-to-browser communication.
    • Added safer handling for missing or empty item values.
  • Maintenance

    • Updated the project to the 5.4.0-SNAPSHOT development version.
    • Added cleanup support for generated frontend and bundling files.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4cd70306-9c53-43b9-8453-1e323d7ec463

📥 Commits

Reviewing files that changed from the base of the PR and between b0e618f and 3b523c2.

📒 Files selected for processing (1)
  • pom.xml
🚧 Files skipped from review as they are similar to previous changes (1)
  • pom.xml

Walkthrough

The project updates to version 5.4.0-SNAPSHOT, removes test Jackson Databind usage, adds generated-file cleanup, and replaces Jackson string serialization with Vaadin JSON values for OrgChart server-to-client updates.

Changes

OrgChart JSON migration

Layer / File(s) Summary
Build and generated-file cleanup
.gitignore, pom.xml
The project version changes to 5.4.0-SNAPSHOT. Test Jackson Databind is removed. The dance profile cleans generated frontend, Node, bundle, and configuration files.
Server-side JSON serialization
src/main/java/com/flowingcode/vaadin/addons/orgchart/OrgChart.java, src/main/java/com/flowingcode/vaadin/addons/orgchart/OrgChartItem.java, src/main/java/com/flowingcode/vaadin/addons/orgchart/client/OrgChartState.java
OrgChart payloads now use Vaadin JsonValue objects. OrgChartItem serializes scalar fields, custom data, and nested children. OrgChartState receives generated getters.
Frontend state initialization
src/main/resources/META-INF/frontend/fc-orgchart.js
initializeOrgChart now accepts a parsed state object and removes JSON string parsing.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Mergeability Score: ⚪ Minimal · up to 3b523

This dependency-removal refactor has no identified merge-blocking risk at the current head and is merge-ready after normal checks and review.

Possibly related PRs

Suggested reviewers: mlopezfc

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes directly address issue #100 by removing Jackson 2 usage and using Elemental JSON for Vaadin 25.3 compatibility.
Out of Scope Changes check ✅ Passed The version, cleanup profile, generated-file ignores, and serialization changes support the stated build and dependency objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: removing Jackson from the add-on's serialization logic and dependencies.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor-100

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pom.xml`:
- Around line 609-617: Align the frontend cleanup and ignore paths with the
canonical generated frontend directory: update the clean-plugin filesets in
pom.xml lines 609-617, and update both ignore rules in .gitignore lines 25-26 to
reference that same directory.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fc2d3570-8691-4bae-adaf-db82b3030ada

📥 Commits

Reviewing files that changed from the base of the PR and between 9a840c8 and b0e618f.

📒 Files selected for processing (6)
  • .gitignore
  • pom.xml
  • src/main/java/com/flowingcode/vaadin/addons/orgchart/OrgChart.java
  • src/main/java/com/flowingcode/vaadin/addons/orgchart/OrgChartItem.java
  • src/main/java/com/flowingcode/vaadin/addons/orgchart/client/OrgChartState.java
  • src/main/resources/META-INF/frontend/fc-orgchart.js

Comment thread pom.xml
@sonarqubecloud

Copy link
Copy Markdown

@javier-godoy
javier-godoy marked this pull request as ready for review August 13, 2026 12:53

@paodb paodb left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested this locally in v25 profile and I'm getting the following error in my IDE console when adding a child to a node in the Edit Chart demo:

[qtp2075982863-59] ERROR com.vaadin.flow.server.DefaultErrorHandler - Unexpected error: Cannot deserialize JSON to type elemental.json.JsonArray: Cannot construct instance of `elemental.json.JsonArray` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
 at [No location information]
java.lang.IllegalArgumentException: Cannot deserialize JSON to type elemental.json.JsonArray: Cannot construct instance of `elemental.json.JsonArray` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
 at [No location information]
        at com.vaadin.flow.internal.JacksonCodec.decodeAs(JacksonCodec.java:259)
        at com.vaadin.flow.server.communication.rpc.DefaultRpcDecoder.decode(DefaultRpcDecoder.java:49)
        at com.vaadin.flow.server.communication.rpc.PublishedServerEventHandlerRpcHandler.decodeArg(PublishedServerEventHandlerRpcHandler.java:332)
        at com.vaadin.flow.server.communication.rpc.PublishedServerEventHandlerRpcHandler.decodeArgs(PublishedServerEventHandlerRpcHandler.java:268)
        at com.vaadin.flow.server.communication.rpc.PublishedServerEventHandlerRpcHandler.invokeMethod(PublishedServerEventHandlerRpcHandler.java:222)
        at com.vaadin.flow.server.communication.rpc.PublishedServerEventHandlerRpcHandler.invokeMethod(PublishedServerEventHandlerRpcHandler.java:200)
        at com.vaadin.flow.server.communication.rpc.PublishedServerEventHandlerRpcHandler.invokeMethod(PublishedServerEventHandlerRpcHandler.java:146)
        at com.vaadin.flow.server.communication.rpc.PublishedServerEventHandlerRpcHandler.handleNode(PublishedServerEventHandlerRpcHandler.java:129)
        at com.vaadin.flow.server.communication.rpc.AbstractRpcInvocationHandler.handle(AbstractRpcInvocationHandler.java:80)
        at com.vaadin.flow.server.communication.ServerRpcHandler.handleInvocationData(ServerRpcHandler.java:640)
        at com.vaadin.flow.server.communication.ServerRpcHandler.lambda$handleInvocations$6(ServerRpcHandler.java:613)
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
        at com.vaadin.flow.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:613)
        at com.vaadin.flow.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:433)
        at com.vaadin.flow.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:364)
        at com.vaadin.flow.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:147)
        at com.vaadin.flow.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:73)
        at com.vaadin.flow.server.VaadinService.handleRequest(VaadinService.java:2014)
        at com.vaadin.flow.server.VaadinServlet.service(VaadinServlet.java:404)
        at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:587)
        at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:764)
        at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1665)
        at org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:170)
        at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:202)
        at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1635)
        at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:527)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:131)
        at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:598)
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:122)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:223)
        at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1580)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:221)
        at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1381)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:176)
        at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:484)
        at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1553)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:174)
        at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1303)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:129)
        at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:149)
        at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:51)
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:122)
        at org.eclipse.jetty.server.Server.handle(Server.java:563)
        at org.eclipse.jetty.server.HttpChannel$RequestDispatchable.dispatch(HttpChannel.java:1598)
        at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:753)
        at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:501)
        at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:287)
        at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:314)
        at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:100)
        at org.eclipse.jetty.io.SelectableChannelEndPoint$1.run(SelectableChannelEndPoint.java:53)
        at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:421)
        at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:390)
        at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:277)
        at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.run(AdaptiveExecutionStrategy.java:199)
        at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:411)
        at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:969)
        at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1194)
        at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1149)
        at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: tools.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `elemental.json.JsonArray` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
 at [No location information]
        at tools.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:70)
        at tools.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1995)
        at tools.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:511)
        at tools.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1525)
        at tools.jackson.databind.deser.AbstractDeserializer.deserialize(AbstractDeserializer.java:254)
        at tools.jackson.databind.deser.DeserializationContextExt.readRootValue(DeserializationContextExt.java:266)
        at tools.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:2610)
        at tools.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:978)
        at tools.jackson.databind.ObjectMapper.treeToValue(ObjectMapper.java:1291)
        at com.vaadin.flow.internal.JacksonCodec.decodeAs(JacksonCodec.java:255)
        ... 58 more

Worth checking before approving this PR.

@javier-godoy

Copy link
Copy Markdown
Member Author

@
Thanks for testing. That error is not caused by this PR — it comes from the @ClientCallable methods onChildrenAdded and onSiblingsAdded taking an elemental.json.JsonArray parameter, which Vaadin 25 cannot decode with JacksonCodec. Those signatures are untouched by this branch, so the failure is pre-existing.

Tracked separately in #102.
@

@javier-godoy
javier-godoy requested a review from paodb August 13, 2026 19:23
@paodb
paodb merged commit 4ee2442 into master Aug 13, 2026
7 checks passed
@paodb
paodb deleted the refactor-100 branch August 13, 2026 19:56
@github-project-automation github-project-automation Bot moved this from In Progress to Pending release in Flowing Code Addons Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Pending release

Development

Successfully merging this pull request may close these issues.

Vaadin 25.3-SNAPSHOT build fails

2 participants