4

We are using ObjectMapper. When using ObjectMapper with RowMapper, should it be declared inside each mapRow (seen below), or outside of mapRow as a class public member? I assume it should be outside as a public class member per this article. Should I declare Jackson's ObjectMapper as a static field?

Currently using Spring boot with SQL Server database. Researching thread safety with thousands/millions of sql rows its getting.

List<Product> productList =  namedParameterJdbcTemplate.query(sqlQuery,
        parameters,
        new ProductMapper(productRequest));


public class ProductMapper implements RowMapper<Product> {
    
    @Override
    public Product mapRow(ResultSet rs, int rowNum) throws SQLException {

        ObjectMapper objectMapper = new ObjectMapper()

        Product product = new Product();

        product.setProductId(rs.getLong("ProductId"));
        product.setProductType(rs.getString("ProductType"));
        product.setLocations(objectMapper.readValue(rs.getString("Locations"), new TypeReference<List<ServiceLocation>>(){}));
            } catch (Exception e) {
                throw new ServiceException(e);
            }
        }

Note: Please don't ask why we are writing this manual mapper with ObjectMapper, we are doing legacy coding, and architects requested to do this.

mattsmith5
  • 540
  • 4
  • 29
  • 67

2 Answers2

2

An ObjectMapper instance is not immutable but, as stated in the documentation:

Mapper instances are fully thread-safe provided that ALL configuration of the instance occurs before ANY read or write calls.

Which means that this code is perfectly thread-safe:

public class ProductMapper implements RowMapper<Product> {
    private ObjectMapper mapper;

    public ProductMapper()
    {
        objectMapper = new ObjectMapper();
    }

    @Override
    public Product mapRow(ResultSet rs, int rowNum) throws SQLException {
        Product product = new Product();
        product.setLocations(objectMapper.readValue(rs.getString("Locations"), new TypeReference<List<ServiceLocation>>(){}));
        return product;
    }
}

However, the TypeReference object is still created for each row, which is not very efficient. A better way is to create an ObjectReader instance via the readerFor() method:

public class ProductMapper implements RowMapper<Product> {
    private ObjectReader objectReader;

    public ProductMapper()
    {
        ObjectMapper objectMapper = new ObjectMapper();
        objectReader = objectMapper.readerFor(new TypeReference<List<ServiceLocation>>(){});
    }

    @Override
    public Product mapRow(ResultSet rs, int rowNum) throws SQLException {
        Product product = new Product();
        product.setLocations(objectReader.readValue(rs.getString("Locations")));
        return product;
    }
}

An ObjectReader instance is immutable and thread-safe.

Olivier
  • 13,283
  • 1
  • 8
  • 24
0

Yes, probably you should declare it is a class level field. It's never recommended to create redundant objects.

Ankit Sharma
  • 1,626
  • 1
  • 14
  • 21