You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spark.apache.org by do...@apache.org on 2026/03/23 19:17:41 UTC

(spark-kubernetes-operator) branch main updated: [SPARK-56162] Prevent Jackson from using reflection on final fields during deserialization for `JEP-500`

This is an automated email from the ASF dual-hosted git repository.

dongjoon pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/spark-kubernetes-operator.git


The following commit(s) were added to refs/heads/main by this push:
     new 21b10c2  [SPARK-56162] Prevent Jackson from using reflection on final fields during deserialization for `JEP-500`
21b10c2 is described below

commit 21b10c26b89eef3fd43532e6445516cdec647e52
Author: Dongjoon Hyun <do...@apache.org>
AuthorDate: Mon Mar 23 12:17:30 2026 -0700

    [SPARK-56162] Prevent Jackson from using reflection on final fields during deserialization for `JEP-500`
    
    ### What changes were proposed in this pull request?
    
    This PR resolves Jackson reflection warnings on `final` fields by adding explicit `JsonCreator` and `JsonProperty` annotations to the constructors:
    
    It also replaces Lombok's `AllArgsConstructor` and `RequiredArgsConstructor` with explicitly written constructors on these classes where necessary to allow Jackson to properly map JSON properties to constructor arguments.
    
    ### Why are the changes needed?
    
    To fix warnings introduced ahead of JDK 26 due to **JEP 500 (Prepare to Make Final Mean Final)**.
    
    - https://openjdk.org/jeps/500
    
      > WARNING: Mutating final fields will be blocked in a future release unless final field mutation is enabled
    
    Previously, Jackson was bypassing constructors and using deep reflection (`Field.set()`) to inject values directly into `final` fields during deserialization. This caused warnings such as `WARNING: Final field <fieldName> in class <className> has been mutated reflectively` to be logged repeatedly during the build and test execution.
    
    By explicitly declaring `JsonCreator` constructors, Jackson is forced to initialize these `final` fields via normal constructor calls rather than deep reflection, eliminating the warnings and ensuring compatibility with future JDK releases where this reflective mutation will be strictly blocked.
    
    ### Does this PR introduce _any_ user-facing change?
    
    No.
    
    ### How was this patch tested?
    
    Pass the CIs.
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    Generated-by: `Gemini 3.1 Pro (High)` on `Antigravity`
    
    Closes #580 from dongjoon-hyun/SPARK-56162.
    
    Authored-by: Dongjoon Hyun <do...@apache.org>
    Signed-off-by: Dongjoon Hyun <do...@apache.org>
---
 .../operator/status/ApplicationAttemptInfo.java    | 10 ++++++++--
 .../operator/status/ApplicationAttemptSummary.java |  9 +++++++--
 .../k8s/operator/status/ApplicationStatus.java     | 11 +++++++----
 .../spark/k8s/operator/status/BaseAttemptInfo.java | 23 ++++++++++++++++------
 .../k8s/operator/status/BaseAttemptSummary.java    |  9 +++++++--
 .../spark/k8s/operator/status/BaseStatus.java      | 11 +++++++----
 .../k8s/operator/status/ClusterAttemptSummary.java |  7 ++++++-
 .../spark/k8s/operator/status/ClusterStatus.java   | 11 +++++++----
 8 files changed, 66 insertions(+), 25 deletions(-)

diff --git a/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/ApplicationAttemptInfo.java b/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/ApplicationAttemptInfo.java
index c9bf414..f1649e1 100644
--- a/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/ApplicationAttemptInfo.java
+++ b/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/ApplicationAttemptInfo.java
@@ -19,8 +19,10 @@
 
 package org.apache.spark.k8s.operator.status;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import lombok.Setter;
@@ -55,8 +57,12 @@ public class ApplicationAttemptInfo extends BaseAttemptInfo {
     schedulingFailureRestartCounter = 0L;
   }
 
-  public ApplicationAttemptInfo(long id, long restartCounter, long failureRestartCounter,
-                                long schedulingFailureRestartCounter) {
+  @JsonCreator
+  public ApplicationAttemptInfo(
+      @JsonProperty("id") long id,
+      @JsonProperty("restartCounter") long restartCounter,
+      @JsonProperty("failureRestartCounter") long failureRestartCounter,
+      @JsonProperty("schedulingFailureRestartCounter") long schedulingFailureRestartCounter) {
     super(id, restartCounter);
     this.failureRestartCounter = failureRestartCounter;
     this.schedulingFailureRestartCounter = schedulingFailureRestartCounter;
diff --git a/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/ApplicationAttemptSummary.java b/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/ApplicationAttemptSummary.java
index 37ff296..68d6f21 100644
--- a/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/ApplicationAttemptSummary.java
+++ b/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/ApplicationAttemptSummary.java
@@ -21,8 +21,10 @@ package org.apache.spark.k8s.operator.status;
 
 import java.util.SortedMap;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import lombok.ToString;
@@ -41,8 +43,11 @@ public class ApplicationAttemptSummary extends BaseAttemptSummary<ApplicationAtt
   // This is used when state history trimming is enabled
   @Getter protected final SortedMap<Long, ApplicationState> stateTransitionHistory;
 
-  public ApplicationAttemptSummary(ApplicationAttemptInfo attemptInfo,
-                                   SortedMap<Long, ApplicationState> stateTransitionHistory) {
+  @JsonCreator
+  public ApplicationAttemptSummary(
+      @JsonProperty("attemptInfo") ApplicationAttemptInfo attemptInfo,
+      @JsonProperty("stateTransitionHistory")
+          SortedMap<Long, ApplicationState> stateTransitionHistory) {
     super(attemptInfo);
     this.stateTransitionHistory = stateTransitionHistory;
   }
diff --git a/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/ApplicationStatus.java b/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/ApplicationStatus.java
index 26dc36d..9d544f1 100644
--- a/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/ApplicationStatus.java
+++ b/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/ApplicationStatus.java
@@ -26,8 +26,10 @@ import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.EqualsAndHashCode;
 import lombok.ToString;
 
@@ -61,11 +63,12 @@ public class ApplicationStatus
    * @param previousAttemptSummary Summary of the previous application attempt.
    * @param currentAttemptSummary Summary of the current application attempt.
    */
+  @JsonCreator
   public ApplicationStatus(
-      ApplicationState currentState,
-      Map<Long, ApplicationState> stateTransitionHistory,
-      ApplicationAttemptSummary previousAttemptSummary,
-      ApplicationAttemptSummary currentAttemptSummary) {
+      @JsonProperty("currentState") ApplicationState currentState,
+      @JsonProperty("stateTransitionHistory") Map<Long, ApplicationState> stateTransitionHistory,
+      @JsonProperty("previousAttemptSummary") ApplicationAttemptSummary previousAttemptSummary,
+      @JsonProperty("currentAttemptSummary") ApplicationAttemptSummary currentAttemptSummary) {
     super(currentState, stateTransitionHistory, previousAttemptSummary, currentAttemptSummary);
   }
 
diff --git a/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/BaseAttemptInfo.java b/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/BaseAttemptInfo.java
index 44a8783..549e859 100644
--- a/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/BaseAttemptInfo.java
+++ b/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/BaseAttemptInfo.java
@@ -19,13 +19,13 @@
 
 package org.apache.spark.k8s.operator.status;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonInclude;
-import lombok.AllArgsConstructor;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.Builder;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
-import lombok.NoArgsConstructor;
 import lombok.Setter;
 import lombok.ToString;
 
@@ -35,14 +35,25 @@ import lombok.ToString;
  * @since 0.8.0
  */
 @Getter
-@NoArgsConstructor
-@AllArgsConstructor
 @Builder
 @EqualsAndHashCode
 @ToString
 @JsonInclude(JsonInclude.Include.NON_NULL)
 @JsonIgnoreProperties(ignoreUnknown = true)
 public class BaseAttemptInfo {
-  @Builder.Default protected final long id = 0L;
-  @Builder.Default @Setter protected long restartCounter = 0L;
+  protected final long id;
+  @Setter protected long restartCounter;
+
+  public BaseAttemptInfo() {
+    this.id = 0L;
+    this.restartCounter = 0L;
+  }
+
+  @JsonCreator
+  public BaseAttemptInfo(
+      @JsonProperty("id") long id,
+      @JsonProperty("restartCounter") long restartCounter) {
+    this.id = id;
+    this.restartCounter = restartCounter;
+  }
 }
diff --git a/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/BaseAttemptSummary.java b/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/BaseAttemptSummary.java
index f0e701c..05a88fc 100644
--- a/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/BaseAttemptSummary.java
+++ b/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/BaseAttemptSummary.java
@@ -19,11 +19,12 @@
 
 package org.apache.spark.k8s.operator.status;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
-import lombok.RequiredArgsConstructor;
 import lombok.ToString;
 
 /**
@@ -34,9 +35,13 @@ import lombok.ToString;
 @EqualsAndHashCode
 @ToString
 @Getter
-@RequiredArgsConstructor
 @JsonInclude(JsonInclude.Include.NON_NULL)
 @JsonIgnoreProperties(ignoreUnknown = true)
 public class BaseAttemptSummary<I extends BaseAttemptInfo> {
   protected final I attemptInfo;
+
+  @JsonCreator
+  public BaseAttemptSummary(@JsonProperty("attemptInfo") I attemptInfo) {
+    this.attemptInfo = attemptInfo;
+  }
 }
diff --git a/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/BaseStatus.java b/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/BaseStatus.java
index 4e04253..3c5bae8 100644
--- a/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/BaseStatus.java
+++ b/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/BaseStatus.java
@@ -23,8 +23,10 @@ import java.util.Map;
 import java.util.SortedMap;
 import java.util.TreeMap;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import lombok.ToString;
@@ -70,11 +72,12 @@ public class BaseStatus<S, STATE extends BaseState<S>, AS extends BaseAttemptSum
    * @param previousAttemptSummary The summary of the previous attempt.
    * @param currentAttemptSummary The summary of the current attempt.
    */
+  @JsonCreator
   public BaseStatus(
-      STATE currentState,
-      Map<Long, STATE> stateTransitionHistory,
-      AS previousAttemptSummary,
-      AS currentAttemptSummary) {
+      @JsonProperty("currentState") STATE currentState,
+      @JsonProperty("stateTransitionHistory") Map<Long, STATE> stateTransitionHistory,
+      @JsonProperty("previousAttemptSummary") AS previousAttemptSummary,
+      @JsonProperty("currentAttemptSummary") AS currentAttemptSummary) {
     this.currentState = currentState;
     this.stateTransitionHistory = new TreeMap<>(stateTransitionHistory);
     this.previousAttemptSummary = previousAttemptSummary;
diff --git a/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/ClusterAttemptSummary.java b/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/ClusterAttemptSummary.java
index d8fbaf3..0af01ea 100644
--- a/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/ClusterAttemptSummary.java
+++ b/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/ClusterAttemptSummary.java
@@ -21,8 +21,10 @@ package org.apache.spark.k8s.operator.status;
 
 import java.util.SortedMap;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import lombok.ToString;
@@ -40,8 +42,11 @@ import lombok.ToString;
 public class ClusterAttemptSummary extends BaseAttemptSummary<BaseAttemptInfo> {
   protected final SortedMap<Long, ClusterState> stateTransitionHistory;
 
+  @JsonCreator
   public ClusterAttemptSummary(
-      BaseAttemptInfo attemptInfo, SortedMap<Long, ClusterState> stateTransitionHistory) {
+      @JsonProperty("attemptInfo") BaseAttemptInfo attemptInfo,
+      @JsonProperty("stateTransitionHistory")
+          SortedMap<Long, ClusterState> stateTransitionHistory) {
     super(attemptInfo);
     this.stateTransitionHistory = stateTransitionHistory;
   }
diff --git a/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/ClusterStatus.java b/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/ClusterStatus.java
index 4962590..427080a 100644
--- a/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/ClusterStatus.java
+++ b/spark-operator-api/src/main/java/org/apache/spark/k8s/operator/status/ClusterStatus.java
@@ -22,8 +22,10 @@ package org.apache.spark.k8s.operator.status;
 import java.util.Map;
 import java.util.TreeMap;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.EqualsAndHashCode;
 import lombok.ToString;
 
@@ -52,11 +54,12 @@ public class ClusterStatus
    * @param previousAttemptSummary Summary of the previous cluster attempt.
    * @param currentAttemptSummary Summary of the current cluster attempt.
    */
+  @JsonCreator
   public ClusterStatus(
-      ClusterState currentState,
-      Map<Long, ClusterState> stateTransitionHistory,
-      ClusterAttemptSummary previousAttemptSummary,
-      ClusterAttemptSummary currentAttemptSummary) {
+      @JsonProperty("currentState") ClusterState currentState,
+      @JsonProperty("stateTransitionHistory") Map<Long, ClusterState> stateTransitionHistory,
+      @JsonProperty("previousAttemptSummary") ClusterAttemptSummary previousAttemptSummary,
+      @JsonProperty("currentAttemptSummary") ClusterAttemptSummary currentAttemptSummary) {
     super(currentState, stateTransitionHistory, previousAttemptSummary, currentAttemptSummary);
   }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@spark.apache.org
For additional commands, e-mail: commits-help@spark.apache.org