question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Unnecessary JsonProcessingException Catch clause in ObjectMapper.writeValueAsString(Object value)

See original GitHub issue

In ObjectMapper class, method writeValueAsString(Object value) includes a throw declaration of type JsonProcessingException.

Current Method code (minus comments) - Latest release

	@SuppressWarnings("resource")
	public String writeValueAsString(Object value) throws JsonProcessingException {
		// alas, we have to pull the recycler directly here...
		SegmentedStringWriter sw = new SegmentedStringWriter(_jsonFactory._getBufferRecycler());
		try {
			_configAndWriteValue(_jsonFactory.createGenerator(sw), value);
		} catch (JsonProcessingException e) {
			throw e;
		} catch (IOException e) { // shouldn't really happen, but is declared as
									// possibility so:
			throw JsonMappingException.fromUnexpectedIOE(e);
		}
		return sw.getAndClear();
	}

The _configAndWriteValue() call in the snippet above (surrounded by the try - catch block, is only throwing an IOException, which is caught and handled in the seccond catch clause. So the only other part of this try - catch block that could potentially throw the JsonProcessingException is the _jsonFactory.createGenerator(sw) call, where sw is the SegmentedStringWriter which extends Writer.

Looking at how the JsonFactory instance is populated in this class, we can see in the Object mapper constructor:

	public ObjectMapper() {
		this(null, null, null);
	}

which calls:

	public ObjectMapper(JsonFactory jf, DefaultSerializerProvider sp, DefaultDeserializationContext dc) {
		/*
		 * 02-Mar-2009, tatu: Important: we MUST default to using the mapping
		 * factory, otherwise tree serialization will have problems with
		 * POJONodes. 03-Jan-2010, tatu: and obviously we also must pass 'this',
		 * to create actual linking.
		 */
		if (jf == null) {
			_jsonFactory = new MappingJsonFactory(this);
		} else {
			_jsonFactory = jf;
			if (jf.getCodec() == null) { // as per [JACKSON-741]
				_jsonFactory.setCodec(this);
			}
		}
		_subtypeResolver = new StdSubtypeResolver();
		RootNameLookup rootNames = new RootNameLookup();
		// and default type factory is shared one
		_typeFactory = TypeFactory.defaultInstance();

		SimpleMixInResolver mixins = new SimpleMixInResolver(null);
		_mixIns = mixins;
		BaseSettings base = DEFAULT_BASE.withClassIntrospector(defaultClassIntrospector());
		_configOverrides = new ConfigOverrides();
		_serializationConfig = new SerializationConfig(base, _subtypeResolver, mixins, rootNames, _configOverrides);
		_deserializationConfig = new DeserializationConfig(base, _subtypeResolver, mixins, rootNames, _configOverrides);

		// Some overrides we may need
		final boolean needOrder = _jsonFactory.requiresPropertyOrdering();
		if (needOrder ^ _serializationConfig.isEnabled(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)) {
			configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, needOrder);
		}

		_serializerProvider = (sp == null) ? new DefaultSerializerProvider.Impl() : sp;
		_deserializationContext = (dc == null)
				? new DefaultDeserializationContext.Impl(BeanDeserializerFactory.instance) : dc;

		// Default serializer factory is stateless, can just assign
		_serializerFactory = BeanSerializerFactory.instance;
	}

This constructor initializes the JsonFactory by default, as an instance of its MappingJsonFactory implementing subclass.

Looking at this class, we can see it does not actually overide the createGenerator(Writer w) method from com.fasterxml.jackson.core.JsonFactory.

And from com.fasterxml.jackson.core.JsonFactory we can see that all overloaded instances of the createGenerator method are not throwing a JsonProcessingException but rather again an IOException (See link https://github.com/FasterXML/jackson-core/blob/master/src/main/java/com/fasterxml/jackson/core/JsonFactory.java).

So the catch clause for JsonProcessingException can be completely removed from writeValueAsString in ObjectMapper.

Recomended Change

	@SuppressWarnings("resource")
	public String writeValueAsString(Object value) throws JsonProcessingException {
		// alas, we have to pull the recycler directly here...
		SegmentedStringWriter sw = new SegmentedStringWriter(_jsonFactory._getBufferRecycler());
		try {
			_configAndWriteValue(_jsonFactory.createGenerator(sw), value);
		}  catch (IOException e) { // shouldn't really happen, but is declared as
									// possibility so:
			throw JsonMappingException.fromUnexpectedIOE(e);
		}
		return sw.getAndClear();
	}

Unless I have missed something, I think the above refactor could be made without causing serious issues.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:4
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
hazeltroostcommented, Jan 3, 2018

Creating a JsonProcessingException isn’t likely, but it’s easy to court if wanted.

@Test
public void forceJsonParseException() {
    try {
        Object mockItem = mock(Object.class);
        when(mockItem.toString()).thenReturn(mockItem.getClass().getName());
        new ObjectMapper().writeValueAsString(mockItem);
        fail("did not throw JsonProcessingException");
    } catch (JsonProcessingException e) {
        //pass
    }
}
0reactions
cowtowncodercommented, May 24, 2022

@ruckc If you want a change, please file a new issue, explaining exact issue you have. It does not sound the original issue and I think it is confusing to reopen issues after the fact in such cases. But I suspect @yawkat’s comment is valid here as well: re-throwing an exception does not do anything to stack trace – if something is not available it’s due to something else.

But I would specifically need a reproduction of your problem, not just general description.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to get a JsonProcessingException using Jackson
I wanted to do the same thing, and eventually accomplished it by using the Mockito "spy" function, which wraps a real object with...
Read more >
Example usage for com.fasterxml.jackson.core ... - Java2s.com
writeValueAsString (msg_pojo); } catch (JsonProcessingException e) { logger.error("Failed using mapper to write JSON:", e); return msg_pojo.
Read more >
Java Examples for com.fasterxml.jackson.core ... - Javatips.net
This java examples will help you to understand the usage of com.fasterxml.jackson.core.JsonProcessingException. These source code samples are taken from ...
Read more >
ObjectMapper (jackson-databind 2.6.0 API) - FasterXML
Method that can be used to serialize any Java value as a byte array. String · writeValueAsString(Object value). Method that can be used...
Read more >
Jackson Exceptions - Problems and Solutions - Baeldung
Get started with Spring 5 and Spring Boot 2, through the Learn ... User]: can not instantiate from JSON object (need to add/enable...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found