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.

`@JacksonInject` added to property overrides value from the JSON even if `useInput` is `OptBoolean.TRUE`

See original GitHub issue

Hello, I have problem when using @JacksonInject on final field that is initialized using constructor (see the whole example at the end of the message).

The problem is that the correct value from JSON is used when the constructor is called, see the stacktrace:

AnnotatedConstructor.call(Object[]) line: 124	
StdValueInstantiator.createFromObjectWith(DeserializationContext, Object[]) line: 283	
StdValueInstantiator(ValueInstantiator).createFromObjectWith(DeserializationContext, SettableBeanProperty[], PropertyValueBuffer) line: 229	
PropertyBasedCreator.build(DeserializationContext, PropertyValueBuffer) line: 195	
BeanDeserializer._deserializeUsingPropertyBased(JsonParser, DeserializationContext) line: 422	
BeanDeserializer(BeanDeserializerBase).deserializeFromObjectUsingNonDefault(JsonParser, DeserializationContext) line: 1287	
BeanDeserializer.deserializeFromObject(JsonParser, DeserializationContext) line: 326	
BeanDeserializer.deserialize(JsonParser, DeserializationContext) line: 159	
ObjectMapper._readMapAndClose(JsonParser, JavaType) line: 4013	
ObjectMapper.readValue(String, Class<T>) line: 3004	
JacksonInjectTest.testReadValueInjectables()

But later this value is overrided by the default value of the injectable (but useInput is OptBoolean.TRUE) because _injectables != null at BeanDeserializer.deserialize(JsonParser, DeserializationContext, Object) line: 216, full stacktrace:

AnnotatedField.setValue(Object, Object) line: 105	
ValueInjector.inject(DeserializationContext, Object) line: 51	
BeanDeserializer(BeanDeserializerBase).injectValues(DeserializationContext, Object) line: 1520	
BeanDeserializer.deserialize(JsonParser, DeserializationContext, Object) line: 217	
BeanDeserializer._deserializeUsingPropertyBased(JsonParser, DeserializationContext) line: 441	
BeanDeserializer(BeanDeserializerBase).deserializeFromObjectUsingNonDefault(JsonParser, DeserializationContext) line: 1287	
BeanDeserializer.deserializeFromObject(JsonParser, DeserializationContext) line: 326	
BeanDeserializer.deserialize(JsonParser, DeserializationContext) line: 159	
ObjectMapper._readMapAndClose(JsonParser, JavaType) line: 4013	
ObjectMapper.readValue(String, Class<T>) line: 3004	
JacksonInjectTest.testReadValueInjectables()	

This happens even if I set mapper.configure(MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS, false); which is weired.

Here is the whole example:

package com.drooms.semantic.flink.jobs;

import static java.util.Objects.requireNonNull;
import static org.testng.Assert.assertEquals;

import java.io.IOException;

import org.testng.annotations.Test;

import com.fasterxml.jackson.annotation.JacksonInject;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.OptBoolean;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.InjectableValues;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonInjectTest {
	protected static class Some {
		private final String field1;

		@JacksonInject(value = "defaultValueForField2", useInput = OptBoolean.TRUE)
		private final String field2;

		public Some(@JsonProperty("field1") final String field1,
				@JsonProperty("field2") @JacksonInject(value = "defaultValueForField2",
						useInput = OptBoolean.TRUE) final String field2) {
			this.field1 = requireNonNull(field1);
			this.field2 = requireNonNull(field2);
		}

		public String getField1() {
			return field1;
		}

		public String getField2() {
			return field2;
		}
	}

	@Test
	public void testReadValueInjectables() throws JsonParseException, JsonMappingException, IOException {
		final ObjectMapper mapper = new ObjectMapper();
		final InjectableValues injectableValues =
				new InjectableValues.Std().addValue("defaultValueForField2", "somedefaultValue");
		mapper.setInjectableValues(injectableValues);

		final Some actualValueMissing = mapper.readValue("{\"field1\": \"field1value\"}", Some.class);
		assertEquals(actualValueMissing.getField1(), "field1value");
		assertEquals(actualValueMissing.getField2(), "somedefaultValue");

		final Some actualValuePresent =
				mapper.readValue("{\"field1\": \"field1value\", \"field2\": \"field2value\"}", Some.class);
		assertEquals(actualValuePresent.getField1(), "field1value");
		assertEquals(actualValuePresent.getField2(), "somedefaultValue");
		// if I comment @JacksonInject that is next to the property the valid assert is the correct one:
		// assertEquals(actualValuePresent.getField2(), "field2value");
	}
}

In my original case I’m using lombok to generate the constructor and the annotation is copied from property to the constructor parameter (you can check it here: https://github.com/rzwitserloot/lombok/issues/1528#issuecomment-607725333 ). You can check https://stackoverflow.com/a/60987798/2054634 for more information on the context of the problem.

P.S. I’m using jackson v. 2.9.6

Thanks in advance, Plamen

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:9 (5 by maintainers)

github_iconTop GitHub Comments

2reactions
cowtowncodercommented, Apr 5, 2020

Thank you for reporting the issue: without looking into it, sounds legit, hope to have time to look into this soon.

0reactions
ptanovcommented, Apr 16, 2020

Thank you very much!

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to use @JacksonInject(useInput= OptBoolean.FALSE)
If the value is true, input value will override injected value. Default value of useInput is default that has true value." My question:...
Read more >
JacksonInject (Jackson-annotations 2.12.6 API) - javadoc.io
Usually property is not deserialized from JSON, although it possible to have injected value as default and still allow optional override from JSON....
Read more >
com.fasterxml.jackson.annotation.OptBoolean java code examples ...
JacksonInject $Value.equals(...) @Override public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; if (o.
Read more >
Jackson @JacksonInject Example - ConcretePage.com
If the value is true, input value will override injected value. ... has true value. @JacksonInject(value= "catInput", useInput= OptBoolean.
Read more >
Using @JsonInclude to define properties inclusion rules
@JsonInclude annotation can be used to indicate when the annotated property can be serialized. Normally property values are always included, ...
Read more >

github_iconTop Related Medium Post

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