Reputation: 7484
Might be a strange question but indeed I would like to achieve a a bit more coverage on my tests and although I coded against a JsonProcessingException
I can't create a payload that generates this exception, maybe because Jackson is quite smart and converts everything to a string, and even for bad strings it goes around the JSON specs. My problem is that Jackson is quite good :)
I basically want a payload that when I run this, it break with JsonProcessingException
:
String jsonPayload = objectMapper.writeValueAsString(payload);
I've tried some like:
HashMap<String, String> invalidJSONPayload= new HashMap<>();
invalidJSONPayload.put("021",021);
invalidJSONPayload.put("---",021);
invalidJSONPayload.put("~",021);
I'm not fussed with the type, so feel free to suggest another one. An empty object for example, throws JsonMappingException
and I already catch that one as well.
Upvotes: 69
Views: 134017
Reputation: 101
Even though, the question is too old, would like to add this simple solution.
@Test
public void shouldFailObjectMapperWriteValueAsString() {
// Act & Assert
assertThrows(
Exception.class,
() -> new ObjectMapper().writeValueAsString(new Object()));
}
Error message:
No serializer found for class java.lang.Object and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) while converting value = java.lang.Object@2f75a9b1 to json
As mentioned in error, Object.class
does not have any serializer as well as any attributes. So it will automatically fail. No extra classes or mock is required.
Upvotes: 2
Reputation: 171
For me, if a class has no public
fields/methods, writeValueAsString
will throw a JsonMappingException
(no serializer found for class...
)
private static class ClassThatJacksonCannotSerialize {}
private void forceProcessingException() {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.writeValueAsString(new ClassThatJacksonCannotSerialize());
}
catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
Upvotes: 17
Reputation: 1324
Here's how I did it. Let's imagine you have:
@JsonInclude(value = JsonInclude.Include.NON_NULL)
public class MyClass {
@JsonProperty("field") Object myField;
public String toJson() {
try {
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(this);
}
catch (JsonProcessingException jpe) {
throw new IllegalStateException(jpe);
}
}
}
You can add the following test to your suite to cover the catch block:
@Test(expected = RuntimeException.class)
public void triggerJsonProcessingException() {
class SelfRefrencing extends MyClass {
@JsonProperty("self") SelfRefrencing self = this;
}
new SelfRefrencing(new MyClass()).toJson();
}
Upvotes: 0
Reputation: 153
Use this value, it shall break, it broke for me::
ObjectMapper objectMapper = new ObjectMapper();
String jsonStringValue ="{'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}";
try {
MyCustomClass classObject = objectMapper.readValue(jsonStringValue, MyCustomClass.class);
} catch(JsonProcessingException ex) {
//LOGGER / SYSOUT here
}
ERROR::JsonProcessingException / JsonParseException Unexpected character (''' (code 39)): was expecting double-quote to start field name It really worked for me.. cheers..
Upvotes: 1
Reputation: 141
You can get a JsonProcessingException if mapping two fields to the same property.
class InvalidObject {
@JsonProperty("s")
private String x = "value1";
@JsonProperty("s")
private String y = "value2";
}
Exception message is "Multiple fields representing property "s":..."
Upvotes: 14
Reputation: 313
You can get JsonProcessingException
via below code
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class SomePOJOClass
{
// Lets assume there are your fields here.
}
// ...
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode objectNode = new ObjectNode();
objectNode.put("unknown-field-in-the-class", "and-its-value");
SomePOJOClass somePOJOClass = objectMapper.treeToValue(objectNode, SomePOJOClass .class);
Upvotes: 0
Reputation: 21
i was land on this question because i had the same target of the questioner:
Might be a strange question but indeed I would like to achieve a a bit more coverage on my tests
IMHO Mockito solution it's more elegant and not introduce misunderstanding but I challenged a colleague to find another solution and he did. This is the solution:
@Test
@DisplayName("Object To Json KO")
void objectToJsonKOTest() {
KafkaMessageDTO o = new KafkaMessageDTO() {
@Override
public String getAuthCode() {
int a = 2/0;
return super.getAuthCode();
}
};
String s = mapper.writeValueAsString(o);
Assertions.assertTrue(s.isEmpty());
}
This is trash, high level trash :) , but it works and I wanted to share it with you as an alternative to mock
ByeBye
Upvotes: 2
Reputation: 59
Throw exception in getter to simulate JsonProcessingException.
public static class TestData {
public String getEx() throws JsonProcessingException { throw new JsonParseException(null, "test"); }
}
ObjectMapper().writeValueAsString(new TestData());
Upvotes: 4
Reputation: 43
I found this in Jackson Github issue; but it solved my problem and I am able to throw the JsonProcessingException.
@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
}
}
Now how I used this in my code
Need to test this method
public String geResponse(MyObject myObject) {
try {
return objectMapper.writeValueAsString(myObject);
} catch (JsonProcessingException e) {
log.error("Service response JsonParsing error {} ", e.getMessage());
return "Validation Service response JsonParsing error {} "+ e.getMessage();
}
}
This how I test the JsonProcessingException
@SneakyThrows
@Test
public void testGetValidationResponseNegative() {
MyObject mockItem = mock(MyObject.class);
when(mockItem.toString()).thenReturn(mockItem.getClass().getName());
String vr = geResponse(mockItem);
assertTrue(!vr.isEmpty());
}
I hope this helps!!!
Upvotes: 2
Reputation: 5269
Trying to mock using mock(ObjectMapper.class)
will invariably result in Checked exception is invalid for this method! as it is not possible to throw checked exception (JsonProcessingException
extends IOException
). Creating a self referencing value object like other answers suggested could be too convoluted for many cases and looks like a hack.
The easiest way I found is to extend ObjectMapper
and then use that in your test method. You should pass the subclass to SUT
@Test
public void buildJsonSwallowsJsonProcessingException() {
class MyObjectMapper extends ObjectMapper {
@Override
public String writeValueAsString(Object value)
throws com.fasterxml.jackson.core.JsonProcessingException {
throw new com.fasterxml.jackson.core.JsonProcessingException("Forced error") {};
}
}
ObjectMapper objectMapper = new MyObjectMapper();
SUTBean sutbean = new SUTBean(objectMapper);
sutbean.testMethod();
assertTrue(expected, actual);
}
Upvotes: 3
Reputation: 1925
following on @Mike.Mathieson answer
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
public class JacksonTest {
@Test(expected = JsonProcessingException.class)
// actually throws an InvalidDefinitionException (which extends JsonProcessingException)
public void encodeThrowsException() throws JsonProcessingException {
new ObjectMapper().writeValueAsString(new Object());
}
}
note that this test won't work if the ObjectMapper have been configured to disable SerializationFeature.FAIL_ON_EMPTY_BEANS
, e.g.
new ObjectMapper()
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
.writeValueAsString(new Object());
Upvotes: 18
Reputation: 285
I wanted to do the same thing, and eventually accomplished it by using the Mockito "spy" function, which wraps a real object with a mock object. All calls to the mock object get forwarded to the real object, except those you are trying to mock. For example:
ObjectMapper om = Mockito.spy(new ObjectMapper());
Mockito.when( om.writeValueAsString(ErrorObject.class)).thenThrow(new JsonProcessingException("") {});
All usages of om
will be handled by the underlying ObjectMapper instance until an instance of ErrorObject
gets passed in, at which point the JsonProcessingException
will be thrown.
The newJsonProcessingException
is created as an anonymous class, as it is a protected class and only a sub-class can be instantiated.
Upvotes: 26
Reputation: 949
Building off of Liam's answer, mocking the toString()
method with a cycle also causes Jackson to break.
@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
}
}
EDIT: It's way easier than that. A Mockito mock will always throw it. o.o;;
Upvotes: 28
Reputation: 703
You could use something like this:
private static class ClassThatJacksonCannotSerialize {
private final ClassThatJacksonCannotSerialize self = this;
@Override
public String toString() {
return self.getClass().getName();
}
}
Which results in a JsonProcessingException
with message Direct self-reference leading to cycle (through reference chain: ClassThatJacksonCannotSerialize["self"])
Upvotes: 20