How do I get an array value instead of reference from ObjectMapper in Jackson?

I am trying to get a result from an API response and am able to map everything except for columnHeaders, which is an array of ColumnHeaders. I am instead getting a reference to an array. The code is below.

Response Class

public class Response {

    @JsonProperty("searchApiFormatVersion")
    private String searchApiFormatVersion;

    @JsonProperty("searchName")
    private String searchName;

    @JsonProperty("description")
    private String description;

    @JsonProperty("columnHeaders")
    private ColumnHeader[] columnHeaders;

public Response(String searchApiFormatVersion, String searchName, String description,
                    ColumnHeader[] columnHeaders) {
        this.searchApiFormatVersion = searchApiFormatVersion;
        this.searchName = searchName;
        this.description = description;
        this.columnHeaders = columnHeaders;
    }

    public Response(){

    }

    public String getSearchApiFormatVersion() {
        return searchApiFormatVersion;
    }

    public void setSearchApiFormatVersion(String searchApiFormatVersion) {
        this.searchApiFormatVersion = searchApiFormatVersion;
    }

    public String getSearchName() {
        return searchName;
    }

    public void setSearchName(String searchName) {
        this.searchName = searchName;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    
    public ColumnHeader[] getColumnHeaders() {
        return columnHeaders;
    }

    public void setColumnHeaders(ColumnHeader[] columnHeaders) {
        this.columnHeaders = columnHeaders;
    }

    @Override
    public String toString() {
        return "Response{" +
                "searchApiFormatVersion='" + searchApiFormatVersion + '\'' +
                ", searchName='" + searchName + '\'' +
                ", description='" + description + '\'' +
                ", totalRowCount=" + totalRowCount +
                ", returnedRowCount=" + returnedRowCount +
                ", startingReturnedRowNumber=" + startingReturnedRowNumber +
                ", basetype='" + basetype + '\'' +
                ", columnCount=" + columnCount +
                ", columnHeaders=" + columnHeaders +
                '}';
    }
}

ColumnHeader class

public class ColumnHeader {

    @JsonProperty("text")
    private String text;

    @JsonProperty("dataType")
    private String dataType;

    @JsonProperty("hierarchy")
    private int hierarchy;

    @JsonProperty("parentName")
    private String parentName;

    @JsonProperty("isEntity")
    private Boolean isEntity;

    @JsonProperty("isEset")
    private Boolean isEset;

    public ColumnHeader(String text, String dataType, int hierarchy, String parentName, Boolean isEntity, Boolean isEset) {
        this.text = text;
        this.dataType = dataType;
        this.hierarchy = hierarchy;
        this.parentName = parentName;
        this.isEntity = isEntity;
        this.isEset = isEset;
    }

    public ColumnHeader(){

    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getDataType() {
        return dataType;
    }

    public void setDataType(String dataType) {
        this.dataType = dataType;
    }

    public int getHierarchy() {
        return hierarchy;
    }

    public void setHierarchy(int hierarchy) {
        this.hierarchy = hierarchy;
    }

    public String getParentName() {
        return parentName;
    }

    public void setParentName(String parentName) {
        this.parentName = parentName;
    }

    public Boolean getEntity() {
        return isEntity;
    }

    public void setEntity(Boolean entity) {
        isEntity = entity;
    }

    public Boolean getEset() {
        return isEset;
    }

    public void setEset(Boolean eset) {
        isEset = eset;
    }

    @Override
    public String toString() {
        return "ColumnHeader{" +
                "text='" + text + '\'' +
                ", dataType='" + dataType + '\'' +
                ", hierarchy=" + hierarchy +
                ", parentName='" + parentName + '\'' +
                ", isEntity=" + isEntity +
                ", isEset=" + isEset +
                '}';
    }
}

Service Class

public class BudgetEffortResponseService {

    Logger logger = LoggerFactory.getLogger(Response.class);

    public Response getResponseFromStringJsonApiResponse(String stringJsonResponse) throws JsonProcessingException {

        ObjectMapper objectMapper = new ObjectMapper(); //Used to map objects from JSON values specified in Award under @JsonProperty annotation
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        JSONObject stringJsonResponseTurnedIntoJsonObject = new JSONObject(stringJsonResponse);

        logger.info("stringJsonResponseTurnedIntoJsonObject: " + stringJsonResponseTurnedIntoJsonObject);

        return objectMapper.readValue(stringJsonResponseTurnedIntoJsonObject.toString(), Response.class);

    }
}

Main Class

@SpringBootApplication
public class EtlApplication {

    public static final String API_USERNAME = System.getenv("API_USERNAME");
    public static final String API_PASSWORD = System.getenv("API_PASSWORD");
    public static final String API_PREFIX = System.getenv("API_PREFIX");
    public static final String API_PATH = System.getenv("API_PATH");

    public static void main(String[] args) throws URISyntaxException, JsonProcessingException {

        Logger logger = LoggerFactory.getLogger(EtlApplication.class);
        logger.info("--------------------Starting process--------------------");

        AwardRepository awardRepository = new AwardRepository();
        AwardService awardService = new AwardService();
        ApiResponseRowService apiResponseRowService = new ApiResponseRowService();
        ApiResponseRepository apiResponseRepository = new ApiResponseRepository();
        BudgetEffortResponseService budgetEffortResponseService = new BudgetEffortResponseService();

        Date startDateForApiPull = new GregorianCalendar(2023, Calendar.FEBRUARY, 1).getTime();
        Date endDateForApiPull = new GregorianCalendar(2023, Calendar.FEBRUARY, 2).getTime();

        logger.info("============Starting BudgetEffort API pull from Huron===============");

        HttpResponse<String> budgetEffortHttpResponse = apiResponseRepository.getHttpResponseFromApi(startDateForApiPull,
        endDateForApiPull, 1, -1, API_PREFIX, API_PATH,
        API_USERNAME, API_PASSWORD);

        logger.info("BudgetEffortHttpResponse: " + budgetEffortHttpResponse);

        logger.info("============End of BudgetEffort API pull from Huron===============");

        //Get body of http response string
        String budgetEffortResponseString = budgetEffortHttpResponse.body();
        logger.info("BudgetEffortResponseString: " + budgetEffortResponseString);

        Response budgetEffortResponse = budgetEffortResponseService.getResponseFromStringJsonApiResponse(budgetEffortResponseString);

        logger.info("BudgetEffortResponse: " + budgetEffortResponse);

        logger.info("--------------------End of process--------------------");
    }

}

The response. I’m noticing that I’m getting the reference to the array for columnHeaders and not the values. How would I get the values? Thank you.

BudgetEffortResponse: Response{searchApiFormatVersion='1.0', searchName='Personnel Details for Authorized allocations on Active Awards', description='', columnHeaders=[Lcom.example.etl.entity.budgetEffort.ColumnHeader;@7a7471ce}

>Solution :

The response you get is ok. And also the Array is good. The line

logger.info("BudgetEffortResponse: " + budgetEffortResponse);

uses an indirect cast to String of the Object budgetEffortResponse. In this case all toString() methods of the objects are called. What you need to do in order to print out the Objects is to implement/add the toString() method in the class com.example.etl.entity.budgetEffort.ColumnHeader

Update:

As the toString method is already implemented, the above is partially wrong. But there is a way to use a setting of the ObjectMapper:

ObjectMapper mapper = new ObjectMapper();
// pretty print
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(budgetEffortResponse);
logger.info("BudgetEffortResponse: " + json);

Leave a Reply