Skip to content

Map deserialization results in different numeric classes based on json ordering (BigDecimal / Double) when used in combination with @JsonSubTypes #3133

Closed
@mreiterer

Description

@mreiterer

Describe the bug
When deserializing a jsonSubTye which contains a map with numeric values (floats) the order of the json string results in different classes constructed.

I have pasted a complete Junit5 Test which can easily be used to reproduce the issue.

Version information
Happens from 2.12.0 onwards, in 2.11.x its ok.

To Reproduce
If you have a way to reproduce this with:

package test;

import java.util.HashMap;
import java.util.Map;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

@TestInstance(Lifecycle.PER_CLASS)
public class JacksonSubTypeBehaviourTest {

	private static final Logger log = LoggerFactory.getLogger(JacksonSubTypeBehaviourTest.class);

	private ObjectMapper mapper;

	@BeforeAll
	public void before() {
		mapper = new ObjectMapper();
		mapper.disable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
	}

	@Test 
	public void testDeserializeWithDifferentOrdering() throws Exception {
		
		String ordering1 = "{\n"
				+ "			\"type\": \"MAP\",\n"
				+ "			\"map\": {\n"
				+ "				\"doubleValue\": 0.1\n"
				+ "			}\n"
				+ "}";
				
		TestMapContainer model1 = mapper.readValue(ordering1, TestMapContainer.class);
		log.info("clazz: {}",  model1.getMap().get("doubleValue").getClass());
		Assertions.assertTrue(model1.getMap().get("doubleValue") instanceof Double);
		
		
		String ordering2 = "{\n"
				+ "	\"map\": {\n"
				+ "		\"doubleValue\": 0.1\n"
				+ "	},\n"
				+ "	\"type\": \"MAP\"\n"
				+ "	\n"
				+ "}";
		
		TestMapContainer model2 = mapper.readValue(ordering2, TestMapContainer.class);
		
		log.info("clazz: {}",  model2.getMap().get("doubleValue").getClass());
		Assertions.assertTrue(model2.getMap().get("doubleValue") instanceof Double);
		
	}
	
	@JsonTypeInfo(  
		    use = JsonTypeInfo.Id.NAME,  
		    include = JsonTypeInfo.As.PROPERTY,  
		    property = "type")

	@JsonSubTypes({  
	    @Type(value = TestMapContainer.class, name = "MAP"),
	     })  	
	private static interface TestJsonTypeInfoInterface {
		
	}
	
	private static class TestMapContainer implements TestJsonTypeInfoInterface {
		
		private Map<String, ? extends Object> map = new HashMap<>();

		public Map<String, ? extends Object> getMap() {
			return map;
		}

		public void setMap(Map<String, ? extends Object> map) {
			this.map = map;
		}
		
	}
}

Expected behavior
Numeric values (point numbers) should always be created as Double unless stated otherwise with DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS

Metadata

Metadata

Assignees

No one assigned

    Labels

    has-failing-testIndicates that there exists a test case (under `failing/`) to reproduce the issue

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions