-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
feat(#1381): Add a way to specify "inject-only" with @JacksonInject #5175
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 2.x
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
package com.fasterxml.jackson.databind.deser.inject; | ||
|
||
import com.fasterxml.jackson.annotation.JacksonInject; | ||
import com.fasterxml.jackson.annotation.JsonCreator; | ||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import com.fasterxml.jackson.annotation.OptBoolean; | ||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import com.fasterxml.jackson.databind.InjectableValues; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.fasterxml.jackson.databind.exc.MissingInjectableValueExcepion; | ||
import com.fasterxml.jackson.databind.json.JsonMapper; | ||
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertThrows; | ||
|
||
class JacksonInject1381Test extends DatabindTestUtil { | ||
|
||
private static class InputDefault { | ||
|
||
@JacksonInject(value = "key") | ||
private final String field; | ||
|
||
@JsonCreator | ||
public InputDefault(@JsonProperty("field") final String field) { | ||
this.field = field; | ||
} | ||
|
||
public String getField() { | ||
return field; | ||
} | ||
} | ||
|
||
private static class InputTrue { | ||
|
||
@JacksonInject(value = "key", useInput = OptBoolean.TRUE) | ||
private final String field; | ||
|
||
@JsonCreator | ||
public InputTrue(@JsonProperty("field") final String field) { | ||
this.field = field; | ||
} | ||
|
||
public String getField() { | ||
return field; | ||
} | ||
} | ||
|
||
private static class InputFalse { | ||
|
||
@JacksonInject(value = "key", useInput = OptBoolean.FALSE) | ||
private final String field; | ||
|
||
@JsonCreator | ||
public InputFalse(@JsonProperty("field") final String field) { | ||
this.field = field; | ||
} | ||
|
||
public String getField() { | ||
return field; | ||
} | ||
} | ||
|
||
private final String empty = "{}"; | ||
private final String input = "{\"field\": \"input\"}"; | ||
|
||
private final ObjectMapper plainMapper = JsonMapper.builder().build(); | ||
private final ObjectMapper injectedMapper = JsonMapper.builder() | ||
.injectableValues(new InjectableValues.Std().addValue("key", "injected")) | ||
.build(); | ||
|
||
@Test | ||
@DisplayName("input NO, injectable NO, useInput DEFAULT|TRUE|FALSE => exception") | ||
void test1() { | ||
assertThrows(MissingInjectableValueExcepion.class, | ||
() -> plainMapper.readValue(empty, InputDefault.class)); | ||
|
||
assertThrows(MissingInjectableValueExcepion.class, | ||
() -> plainMapper.readValue(empty, InputTrue.class)); | ||
|
||
assertThrows(MissingInjectableValueExcepion.class, | ||
() -> plainMapper.readValue(empty, InputFalse.class)); | ||
} | ||
|
||
@Test | ||
@DisplayName("input NO, injectable YES, useInput DEFAULT|TRUE|FALSE => injected") | ||
void test2() throws JsonProcessingException { | ||
assertEquals("injected", injectedMapper.readValue(empty, InputDefault.class).getField()); | ||
assertEquals("injected", injectedMapper.readValue(empty, InputTrue.class).getField()); | ||
assertEquals("injected", injectedMapper.readValue(empty, InputFalse.class).getField()); | ||
} | ||
|
||
@Test | ||
@DisplayName("input YES, injectable NO, useInput DEFAULT|FALSE => exception") | ||
void test3() { | ||
assertThrows(MissingInjectableValueExcepion.class, | ||
() -> plainMapper.readValue(input, InputDefault.class)); | ||
|
||
assertThrows(MissingInjectableValueExcepion.class, | ||
() -> plainMapper.readValue(input, InputFalse.class)); | ||
} | ||
|
||
@Test | ||
@DisplayName("input YES, injectable NO, useInput TRUE => input") | ||
void test4() throws JsonProcessingException { | ||
assertEquals("input", plainMapper.readValue(input, InputTrue.class).getField()); | ||
} | ||
|
||
@Test | ||
@DisplayName("input YES, injectable YES, useInput DEFAULT|FALSE => injected") | ||
void test5() throws JsonProcessingException { | ||
assertEquals("injected", injectedMapper.readValue(input, InputDefault.class).getField()); | ||
assertEquals("injected", injectedMapper.readValue(input, InputFalse.class).getField()); | ||
} | ||
|
||
@Test | ||
@DisplayName("input YES, injectable YES, useInput TRUE => input") | ||
void test6() throws JsonProcessingException { | ||
assertEquals("input", injectedMapper.readValue(input, InputTrue.class).getField()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package com.fasterxml.jackson.databind.deser.inject; | ||
|
||
import com.fasterxml.jackson.annotation.JacksonInject; | ||
import com.fasterxml.jackson.annotation.JsonCreator; | ||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import com.fasterxml.jackson.annotation.OptBoolean; | ||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import com.fasterxml.jackson.databind.InjectableValues; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.fasterxml.jackson.databind.exc.MissingInjectableValueExcepion; | ||
import com.fasterxml.jackson.databind.json.JsonMapper; | ||
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertThrows; | ||
|
||
class JacksonInject1381WithOptionalTest extends DatabindTestUtil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This class shows how the behavior changes for all the combinations of the other test class when all injected fields are optional. Do you think we still need a I feel like combining |
||
|
||
private static class InputDefault { | ||
|
||
@JacksonInject(value = "key", optional = OptBoolean.TRUE) | ||
private final String field; | ||
|
||
@JsonCreator | ||
public InputDefault(@JsonProperty("field") final String field) { | ||
this.field = field; | ||
} | ||
|
||
public String getField() { | ||
return field; | ||
} | ||
} | ||
|
||
private static class InputTrue { | ||
|
||
@JacksonInject(value = "key", useInput = OptBoolean.TRUE, optional = OptBoolean.TRUE) | ||
private final String field; | ||
|
||
@JsonCreator | ||
public InputTrue(@JsonProperty("field") final String field) { | ||
this.field = field; | ||
} | ||
|
||
public String getField() { | ||
return field; | ||
} | ||
} | ||
|
||
private static class InputFalse { | ||
|
||
@JacksonInject(value = "key", useInput = OptBoolean.FALSE, optional = OptBoolean.TRUE) | ||
private final String field; | ||
|
||
@JsonCreator | ||
public InputFalse(@JsonProperty("field") final String field) { | ||
this.field = field; | ||
} | ||
|
||
public String getField() { | ||
return field; | ||
} | ||
} | ||
|
||
private final String empty = "{}"; | ||
private final String input = "{\"field\": \"input\"}"; | ||
|
||
private final ObjectMapper plainMapper = JsonMapper.builder().build(); | ||
private final ObjectMapper injectedMapper = JsonMapper.builder() | ||
.injectableValues(new InjectableValues.Std().addValue("key", "injected")) | ||
.build(); | ||
|
||
@Test | ||
@DisplayName("optional YES, input NO, injectable NO, useInput DEFAULT|TRUE|FALSE => exception") | ||
void test1() { | ||
assertThrows(MissingInjectableValueExcepion.class, | ||
() -> plainMapper.readValue(empty, InputDefault.class)); | ||
|
||
assertThrows(MissingInjectableValueExcepion.class, | ||
() -> plainMapper.readValue(empty, InputTrue.class)); | ||
|
||
assertThrows(MissingInjectableValueExcepion.class, | ||
() -> plainMapper.readValue(empty, InputFalse.class)); | ||
} | ||
|
||
@Test | ||
@DisplayName("optional YES, input NO, injectable YES, useInput DEFAULT|TRUE|FALSE => injected") | ||
void test2() throws JsonProcessingException { | ||
assertEquals("injected", injectedMapper.readValue(empty, InputDefault.class).getField()); | ||
assertEquals("injected", injectedMapper.readValue(empty, InputTrue.class).getField()); | ||
assertEquals("injected", injectedMapper.readValue(empty, InputFalse.class).getField()); | ||
} | ||
|
||
@Test | ||
@DisplayName("optional YES, input YES, injectable NO, useInput DEFAULT|TRUE|FALSE => input") | ||
void test3() throws JsonProcessingException { | ||
assertEquals("input", plainMapper.readValue(input, InputDefault.class).getField()); | ||
assertEquals("input", plainMapper.readValue(input, InputFalse.class).getField()); | ||
assertEquals("input", plainMapper.readValue(input, InputTrue.class).getField()); | ||
} | ||
|
||
@Test | ||
@DisplayName("optional YES, input YES, injectable YES, useInput DEFAULT|FALSE => injected") | ||
void test4() throws JsonProcessingException { | ||
assertEquals("injected", injectedMapper.readValue(input, InputDefault.class).getField()); | ||
assertEquals("injected", injectedMapper.readValue(input, InputFalse.class).getField()); | ||
} | ||
|
||
@Test | ||
@DisplayName("optional YES, input YES, injectable YES, useInput TRUE => input") | ||
void test5() throws JsonProcessingException { | ||
assertEquals("input", injectedMapper.readValue(input, InputTrue.class).getField()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
package com.fasterxml.jackson.databind.tofix; | ||
package com.fasterxml.jackson.databind.deser.inject; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. moved since this should not fail anymore |
||
|
||
import java.util.Objects; | ||
|
||
|
@@ -10,7 +10,6 @@ | |
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.fasterxml.jackson.databind.json.JsonMapper; | ||
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil; | ||
import com.fasterxml.jackson.databind.testutil.failure.JacksonTestFailureExpected; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
||
|
@@ -41,7 +40,6 @@ public String getField2() { | |
} | ||
|
||
// [databind#2678] | ||
@JacksonTestFailureExpected | ||
@Test | ||
void readValueInjectables() throws Exception { | ||
final InjectableValues injectableValues = | ||
|
@@ -57,8 +55,6 @@ void readValueInjectables() throws Exception { | |
final Some actualValuePresent = mapper.readValue( | ||
"{\"field1\": \"field1value\", \"field2\": \"field2value\"}", Some.class); | ||
assertEquals("field1value", actualValuePresent.getField1()); | ||
|
||
// if I comment @JacksonInject that is next to the property the valid assert is the correct one: | ||
assertEquals("field2value", actualValuePresent.getField2()); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to
useInput
's javadocs:This combination:
input YES, injectable YES, useInput DEFAULT
should actually behave as if we haduseInput = TRUE
, that is dropping the injected value and returning the input.Nevertheless, since
useInput
never worked that way, this would mean introducing breaking changes. My suggestion is to keep things as per this test and change the javadoc accordingly: