Search code examples
javajacksoninner-classesjson-deserializationmapper

Selectively map a part of JSON data to nested class using jackson mapper


I am trying to map JSON data into a Java Class using jackson mapper. While my JSON data is one flat object, with no nesting, I would like to map part of the data to its inner Class.

To illustrate my point, if you look at the JSON data below, security_name and market_cap fields are mapped directly to the Security class. But the 1_month_profit, 3_month_profit, 6_month_profit fields need to map to an inner class - Profit class (eg. 1_month_profit to private Double oneMonthProfit of the Profit class.

Currently, when I deserialize the JSON data, I have all the correct mappings for the Parent class(Security) variables, but the Child class(Profit) variables are not being assigned.

A snapshot of the deserialized data:

{ 
  "security_name": "Apple", 
  "market_cap": 13,000,000,000,  
  "profit": { 
     "1_month_profit": null, // <-- not being assigned.. 
     "3_month_profit": null, // <-- not being assigned.. 
     "6_month_profit": null  // <-- not being assigned.. 
   },
  ...   
 } 

My JSON data is as follows:

{ 
  "security_name": "Apple", 
  "market_cap": 13,000,000,000,  
  "1_month_profit": 1.2, 
  "3_month_profit": -2.0, 
  "6_month_profit": 3.0 
      ...
 } 

The Security class maps the entire JSON data as follows:

public class Security {
   private String securityName;
   private Integer marketCap; 
   private Profit profit = new Profit();

   public String getSecurityName() { 
     return securityName; 
   } 

   @JsonProperty("security_name") 
   public void setSecurityName(String securityName) { 
     this.securityName = securityName; 
   }

   public Integer getMarketCap() { 
     return marketCap; 
   }

   @JsonProperty("market_cap") 
   public void setMarketCap(String marketCap) { 
     this.marketCap= marketCap; 
   }

   @JsonProperty("profit")
   public Profit getProfit() { 
     return profit; 
   }

   public class Profit {
     private Double oneMonthProfit;
     private Double threeMonthProfit;
     private Double sixMonthProfit;

     public Double getOneMonthProfit() {
       return oneMonthProfit;
     }

     @JsonProperty("1_month_profit") // <-- this has no effect. 
     public void setOneMonthProfit(Double oneMonthProfit) {
       this.oneMonthProfit = oneMonthProfit;
     }


     public Double getThreeMonthProfit() {
       return threeMonthProfit;
     }

     @JsonProperty("3_month_profit")
     public void setThreeMonthProfit(Double threeMonthProfit) {
       this.threeMonthProfit = threeMonthProfit;
     }


     public Double getSixMonthProfit() {
       return sixMonthProfit;
     }

     @JsonProperty("6_month_profit")
     public void setSixMonthProfit(Double sixMonthProfit) {
       this.sixMonthProfit = sixMonthProfit;
     }
   } 
}

I was hoping that adding @JsonProperty annotation in the inner Class would solve the issue, but unfortunately this didn't have any effect.

I feel like there must be a way to do this using jackson mapper, but I haven't been able to find a way to achieve this yet.. Your help will be much appreciated! Thank in advance.


Solution

  • You can create the corresponding setters on the Security class itself which maps it to the nested Profit object.

    Here are the modified classes for Security and Profit.

    class Security {
        private String securityName;
        private Integer marketCap;
        private Profit profit = new Profit();
    
        public String getSecurityName() {
            return securityName;
        }
    
        @JsonProperty("security_name")
        public void setSecurityName(String securityName) {
            this.securityName = securityName;
        }
    
        public Integer getMarketCap() {
            return marketCap;
        }
    
        @JsonProperty("market_cap")
        public void setMarketCap(Integer marketCap) {
            this.marketCap = marketCap;
        }
    
        @JsonProperty("profit")
        public Profit getProfit() {
            return profit;
        }
    
        @JsonProperty("1_month_profit")
        public void setOneMonthProfit(Double oneMonthProfit) {
            this.profit.oneMonthProfit = oneMonthProfit;
        }
    
        @JsonProperty("3_month_profit")
        public void setThreeMonthProfit(Double threeMonthProfit) {
            this.profit.threeMonthProfit = threeMonthProfit;
        }
    
        @JsonProperty("6_month_profit")
        public void setSixMonthProfit(Double sixMonthProfit) {
            this.profit.sixMonthProfit = sixMonthProfit;
        }
    
        class Profit {
            private Double oneMonthProfit;
    
            private Double threeMonthProfit;
    
            private Double sixMonthProfit;
    
            @Override
            public String toString() {
                return "Profit [oneMonthProfit=" + oneMonthProfit + ", threeMonthProfit=" + threeMonthProfit
                        + ", sixMonthProfit=" + sixMonthProfit + "]";
            }
        }
    
        @Override
        public String toString() {
            return "Security [securityName=" + securityName + ", marketCap=" + marketCap + ", profit=" + profit + "]";
        }
    }
    

    And then you have the values set. Here is the output for my run.

    Security [securityName=Apple, marketCap=130000, profit=Profit [oneMonthProfit=1.2, threeMonthProfit=-2.0, sixMonthProfit=3.0]]