I would recommend going with a Deserializer as Foo1 might actually be serialized elsewhere and we might only have it's serialized data to convert. And that is what is our goal here.

Create a SimpleModule that deserializes List type

public class ListDeserializer extends StdDeserializer<List> {

    public ListDeserializer() {
        super(List.class);
    }

    @Override
    public List deserialize(JsonParser p, DeserializationContext ctxt)
            throws IOException {
        if (p.getCurrentName().equals("result") || p.getCurrentName().equals("attachments")) {
            JsonNode node = p.getCodec().readTree(p);
            return new ObjectMapper().readValue(node.asText(), List.class);
        }
        return null;
    }
}

The above deserializer only recognizes result and attachments and ignores the rest. So this is a very specific deserializer for List in Foo2 class.

My test Foo1 and Foo2 are as follows

public class Foo1 {

    String result = "[\"abcd\", \"xyz\"]";

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }
}

public class Foo2 {

    List result;

    public List getResult() {
        return result;
    }

    public void setResult(List result) {
        this.result = result;
    }
}

I tested the above code as follows

// Module to help deserialize List objects
SimpleModule listModule = new SimpleModule();
listModule.addDeserializer(List.class, new ListDeserializer());

ObjectMapper objectMapper = new ObjectMapper().registerModules(listModule);
Foo2 foo2 = objectMapper.convertValue(new Foo1(), Foo2.class);
System.out.println(foo2.getResult());

And the output is

[abcd, xyz]
Answer from Sunil Dabburi on Stack Overflow
🌐
Adobe Developer
developer.adobe.com › experience-manager › reference-materials › cloud-service › javadoc › com › fasterxml › jackson › databind › ObjectMapper.html
ObjectMapper (The Adobe Experience Manager SDK 2022.11.9850.20221116T162329Z-220900)
objectMapper.convertValue(n, valueClass); Note: inclusion of throws JsonProcessingException is not accidental since while there can be no input decoding problems, it is possible that content does not match target type: in such case various DatabindExceptions are possible.
Top answer
1 of 2
1

I would recommend going with a Deserializer as Foo1 might actually be serialized elsewhere and we might only have it's serialized data to convert. And that is what is our goal here.

Create a SimpleModule that deserializes List type

public class ListDeserializer extends StdDeserializer<List> {

    public ListDeserializer() {
        super(List.class);
    }

    @Override
    public List deserialize(JsonParser p, DeserializationContext ctxt)
            throws IOException {
        if (p.getCurrentName().equals("result") || p.getCurrentName().equals("attachments")) {
            JsonNode node = p.getCodec().readTree(p);
            return new ObjectMapper().readValue(node.asText(), List.class);
        }
        return null;
    }
}

The above deserializer only recognizes result and attachments and ignores the rest. So this is a very specific deserializer for List in Foo2 class.

My test Foo1 and Foo2 are as follows

public class Foo1 {

    String result = "[\"abcd\", \"xyz\"]";

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }
}

public class Foo2 {

    List result;

    public List getResult() {
        return result;
    }

    public void setResult(List result) {
        this.result = result;
    }
}

I tested the above code as follows

// Module to help deserialize List objects
SimpleModule listModule = new SimpleModule();
listModule.addDeserializer(List.class, new ListDeserializer());

ObjectMapper objectMapper = new ObjectMapper().registerModules(listModule);
Foo2 foo2 = objectMapper.convertValue(new Foo1(), Foo2.class);
System.out.println(foo2.getResult());

And the output is

[abcd, xyz]
2 of 2
0

Option 1 : Just annotate the getter method of the Foo1.class

@JsonProperty("comments")
        public List getComments() {
            List list = new ArrayList();
            list.add(comments);
            return list;
        }

 @JsonProperty("attachments")
        public List getAttachments() {
            List list = new ArrayList();
            list.add(attachments);
            return list;
        }


Foo1 foo1 = new Foo1(Long.valueOf(1),"a","aaa",true,"abc","def");
System.out.println(new ObjectMapper().writeValueAsString(foo1));
Foo2 foo2 = new ObjectMapper().convertValue(foo1, Foo2.class);
System.out.println(new ObjectMapper().writeValueAsString(foo2));

Option 2 : use jackson-custom-serialization

ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Foo1.class,new ListSerializer());
mapper.registerModule(simpleModule);


public class ListSerializer extends StdSerializer<Foo1> {

    public ListSerializer() {
        this(null);
    }

    protected ListSerializer(Class<Blah.Foo1> t) {
        super(t);
    }

    public void serialize(Blah.Foo1 foo1, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeStartObject();
        List list = new ArrayList();
        list.add(foo1.getComments());

        List list1 = new ArrayList();
        list1.add(foo1.getAttachments());

        jsonGenerator.writeObjectField("id",foo1.getId());
        jsonGenerator.writeObjectField("code",foo1.getCode());
        jsonGenerator.writeObjectField("name",foo1.getName());
        jsonGenerator.writeObjectField("rState",foo1.getrState());
        jsonGenerator.writeObjectField("comments",list);
        jsonGenerator.writeObjectField("attachments",list1);
        jsonGenerator.writeEndObject();
    }
}


Foo1 foo1 = new Foo1(Long.valueOf(1),"a","aaa",true,"abc","def");
System.out.println(mapper.writeValueAsString(foo1));
Foo2 foo2 = mapper.convertValue(foo1, Foo2.class);
System.out.println(new ObjectMapper().writeValueAsString(foo2));
🌐
Medium
medium.com › @salvipriya97 › objectmapper-and-its-methods-examples-in-java-4a4cab75cb6b
ObjectMapper and its methods examples in Java | by Priya Salvi | Medium
June 25, 2024 - import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Map; public class Main { public static void main(String[] args) { ObjectMapper objectMapper = new ObjectMapper(); Person person = new Person("John", 30); try { Map<String, Object> map = objectMapper.convertValue(person, Map.class); System.out.println(map); // Output: {name=John, age=30} } catch (Exception e) { e.printStackTrace(); } } }
🌐
Fasterxml
fasterxml.github.io › jackson-databind › javadoc › 2.8 › com › fasterxml › jackson › databind › ObjectMapper.html
ObjectMapper (jackson-databind 2.8.0 API)
objectMapper.convertValue(n, ... of treeToValue(com.fasterxml.jackson.core.TreeNode, java.lang.Class<T>); given a value (usually bean), will construct equivalent JSON Tree representation....
🌐
GitHub
github.com › FasterXML › jackson-databind › issues › 3151
`ObjectMapper.convertValue()` does not work with `@JsonTypeInfo` · Issue #3151 · FasterXML/jackson-databind
May 13, 2021 - package my.jackson.test; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import static org.junit.Assert.*; @Slf4j public class ClientExceptionTest { @Test public void serializeDeserializeTest() throws JsonProcessingException { ClientException clientException = new ClientException(); clientException.setExceptionId("someId"); clientException.setExceptionCategory("someCat"); clientException.setText("someText"); ObjectMapper mapper = new ObjectMapper(); String clientExceptionString = mapper.writeValueAsString(clientException); ClientException actual = mapper.convertValue(clientExceptionString, ClientException.class); assertEquals(clientException, actual); } } Expected behavior Object serialized by ObjectMapper can be deserialized by ObjectMapper.
Published   May 13, 2021
Author   geohuk
🌐
Javadoc.io
javadoc.io › doc › com.fasterxml.jackson.core › jackson-databind › 2.4.0 › com › fasterxml › jackson › databind › ObjectMapper.html
ObjectMapper - jackson-databind 2.4.0 javadoc
Bookmarks · Latest version of com.fasterxml.jackson.core:jackson-databind · https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-databind · Current version 2.4.0 · https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-databind/2.4.0 · package-list path (used for javadoc generation ...
🌐
Google Groups
groups.google.com › g › jackson-user › c › jTiQZDEsV0Q
Re: [jackson-user] Question about how ObjectMapper convertValue works internally
Correct. And back to original question: convertValue() is to most efficient general-purpose way to bind data from JSON Tree Model into POJOs. It does avoid actual writing of JSON as text, and as Pascal explained, will use internal equivalent of token stream to use a source.
🌐
Tabnine
tabnine.com › home page › code › java › com.fasterxml.jackson.databind.objectmapper
com.fasterxml.jackson.databind.ObjectMapper.convertValue java code examples | Tabnine
boolean sameLoadSpec(DataSegment s1, DataSegment s2) { final S3LoadSpec s1LoadSpec = (S3LoadSpec) mapper.convertValue(s1.getLoadSpec(), LoadSpec.class); final S3LoadSpec s2LoadSpec = (S3LoadSpec) mapper.convertValue(s2.getLoadSpec(), LoadSpec.class); return Objects.equal(s1LoadSpec.getBucket(), s2LoadSpec.getBucket()) && Objects.equal( s1LoadSpec.getKey(), s2LoadSpec.getKey() ); } } ... @Test(expected = IllegalArgumentException.class) public void testTypeTypo() { Map<String, Object> greaterMap = ImmutableMap.of( "type", "nonExistingType", "aggregation", "agg", "value", 1.3 ); ObjectMapper mapper = new DefaultObjectMapper(); // noinspection unused HavingSpec spec = mapper.convertValue(greaterMap, HavingSpec.class); }
Find elsewhere
🌐
TutorialsPoint
tutorialspoint.com › jackson › jackson_objectmapper.htm
Jackson - ObjectMapper Class
ObjectMapper class ObjectMapper provides functionality for reading and writing JSON, either to and from basic POJOs (Plain Old Java Objects), or to and from a general-purpose JSON Tree Model (JsonNode), as well as related functionality for performing conversions.
🌐
Java2s
java2s.com › example › java-api › com › fasterxml › jackson › databind › objectmapper › convertvalue-2-4.html
Example usage for com.fasterxml.jackson.databind ObjectMapper convertValue
@RequestMapping(value = "/api/proxy/event", method = RequestMethod.POST) public JsonNode postEvent(@RequestBody ObjectNode object) throws Exception { ObjectMapper mapper = new ObjectMapper(); ProviderOptions options = mapper.convertValue(object.get("options"), ProviderOptions.class); EventProvider eventProvider = providerService .getEventProvider(mongoTenantRepository.findOne(options.getTenantId())); return eventProvider.postEvent(object.get("caliperEvent"), options); }
🌐
GitHub
github.com › FasterXML › jackson-databind › issues › 4661
ObjectMapper convertValue does not check if the value is already of target type · Issue #4661 · FasterXML/jackson-databind
August 13, 2024 - @Test void testConvertRecursive() { var convertedTp = new ObjectMapper().convertValue(new Recursive(), Recursive.class); assertNotNull(convertedTp); } public record Recursive(String name) { Recursive() { this("test"); } public Recursive getSelf() { return new Recursive(); } }
Author   lorenzbaier
🌐
GitHub
github.com › FasterXML › jackson-databind › issues › 3586
ObjectMapper.convertValue() should throw JsonProcessingException · Issue #3586 · FasterXML/jackson-databind
August 26, 2022 - Version: 2.13.1 Doc of treeToValue() says: Functionally equivalent to: objectMapper.convertValue(n, valueClass); Note: inclusion of {@code throws JsonProcessingException} is not accidental since while there can be no input decoding probl...
Author   ewirch
🌐
GitHub
github.com › square › retrofit › issues › 1656
ObjectMapper.convertValue(Object, CustomClass.class) causes infinite loop · Issue #1656 · square/retrofit
March 7, 2016 - public class CustomConverter extends StdConverter<Object, CustomClass> { @Override public CustomClass convert(Object value) { CustomClass cc = null; //Object is of type LinkedHashmap //Try to convert it to our CustomClass class ObjectMapper mapper = new ObjectMapper(); //This is where the code loops. The statement is executed over and over again without executing. try { cc = mapper.convertValue(value, CustomClass.class); } catch(Exception ex) { cc = null; } if(cc == null) { //Mapping failed, so the 'value' is of another type OtherCustomClass occ = mapper.convertValue(value, OtherCustomClass.class); cc = new CustomClass(); //Do mapping of OtherCustomClass to CustomClass here } //Other code here // ...
Author   SanderVH
🌐
How to do in Java
howtodoinjava.com › home › java basics › convert an object to map in java
Convert an Object to Map in Java
September 19, 2022 - Employee employee = new Employee(1, "Alex", LocalDate.of(1995, 1, 2), List.of("Delhi", "Nevada"), List.of(new Role(11, "Finance"), new Role(12, "HR"))); System.out.println(convertObjectToMapUsingObjectMapper(employee)); //The conversion method static Map<String, String> convertObjectToMapUsingObjectMapper(Employee employee) { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new JavaTimeModule()); objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd")); return objectMapper.convertValue(employee, Map.class); }
🌐
Baeldung
baeldung.com › home › java › java collections › java map › converting object to map in java
Converting Object To Map in Java | Baeldung
January 8, 2024 - @Test public void givenJavaObject_whenUsingJackson_thenConvertToMap() { ObjectMapper objectMapper = new ObjectMapper(); Map<String, Object> map = objectMapper .convertValue(employee, new TypeReference<Map<String, Object>>() {}); Assert.assertEquals(employee.getName(), map.get("name")); Assert.assertEquals(employee.getAge(), map.get("salary")); }
Top answer
1 of 2
5

That's depends what the input is.

  • (Map<String, Object>) o is used for casting conversion, so the runtime type of o must be Map, otherwise ClassCastException will be thrown:

    CopyObject o = new HashMap<>();
    Map<String, Object> map = (Map<String, Object>) o; // ok
    
    Object o = new ArrayList<>();
    Map<String, Object> map = (Map<String, Object>) o; //ClassCastException
    
    Object o = new String();
    Map<String, Object> map = (Map<String, Object>) o; //ClassCastException
    
  • ObjectMapper().readValue(String content, JavaType valueType):

    Method to deserialize JSON content from given JSON content String.

    which means the input should be a String in valid json format. For example:

    CopyObject input = "{\"key1\":{},\"key2\":{}}";
    Map<String, Object> map = new ObjectMapper().readValue((String) input, new TypeReference<Map<String, Object>>() {});
    
    System.out.println(map.size()); // 2
    
2 of 2
3

There is no "better". There are practical differences. But first, both options use type casting, and this raises the question "how are these two considered alternatives at all?"

Casting will only work if some object passes the instanceof Map test (first option), or if o passes the instanceof String test (second option).

In other words, the answer depends on the runtime class of some object.

So either this will fail with a class cast exception:

Copy(Map<String, Object>) o;

Or this will fail with the same exception:

Copy(String) o 

Assuming the type checks will pass one way or the other, there are differences to be considered:

  • If some object is compatible with Map<String, Object>, then casting should be preferred as it offers a performance advantage (considering objectMapper.convertValue as the alternative). In fact, readValue isn't even an option as the cast to string will fail.
  • If some object is a String, then you have no choice but to call readValue, as you need to parse JSON.

As noted above, there's also objectMapper.convertValue, which in a smart way checks first instanceof before performing the conversion through JSON parsing. It's meant to convert objects from one type to another, if the two types have the same fields.

🌐
Medium
salithachathuranga94.medium.com › how-to-utilize-jackson-library-for-json-158568637a6c
How to utilize Jackson library for JSON | by Salitha Chathuranga | Medium
November 20, 2021 - String studentJsonString = "{\"name\":\"salitha\",\"first_name\":\"salitha\",\"last_name\":\"chathuranga\",\"age\":28,\"skills\":[\"Java\"]}"; JsonNode studentNode = mapper.readTree(studentJsonString); Student student = mapper.convertValue(studentNode, Student.class);
🌐
Red Hat
access.redhat.com › webassets › avalon › d › red-hat-jboss-enterprise-application-platform › 7.1.beta › javadocs › com › fasterxml › jackson › databind › ObjectMapper.html
ObjectMapper (Red Hat JBoss Enterprise Application Platform 7.1.0.Beta1 public API)
objectMapper.convertValue(n, ... of treeToValue(com.fasterxml.jackson.core.TreeNode, java.lang.Class<T>); given a value (usually bean), will construct equivalent JSON Tree representation....
🌐
Fasterxml
fasterxml.github.io › jackson-databind › javadoc › 2.9 › com › fasterxml › jackson › databind › ObjectMapper.html
ObjectMapper (jackson-databind 2.9.0 API)
objectMapper.convertValue(n, ... of treeToValue(com.fasterxml.jackson.core.TreeNode, java.lang.Class<T>); given a value (usually bean), will construct equivalent JSON Tree representation....