Skip to content

Commit

Permalink
Merge pull request #1163 from folio-org/RMB-1000-ObjectMapperTool.val…
Browse files Browse the repository at this point in the history
…ueAsString

RMB-1000: Provide ObjectMapperTool.valueAsString
  • Loading branch information
julianladisch authored Jul 2, 2024
2 parents 68a7928 + b1ca157 commit 2fded21
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 14 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2517,7 +2517,9 @@ RMB handles all routing, so this is abstracted from the developer. However, ther

#### De-Serializers

At runtime RMB will serialize/deserialize the received JSON in the request body of PUT, PATCH and POST requests into a POJO and pass this on to an implementing function, as well as the POJO returned by the implementing function into JSON. A module can implement its own version of this. For example, the below will register a de-serializer that will tell RMB to set a User to not active if the expiration date has passed. This will be run when a User JSON is passed in as part of a request
At runtime RMB will serialize/deserialize the received JSON in the request body of PUT, PATCH and POST requests into a POJO and pass this on to an implementing function, as well as the POJO returned by the implementing function into JSON. The ObjectMapperTool provides the serializer and de-serializer. Note that `JsonObject.mapFrom` is incompatible, use `ObjectMapperTool.valueAsString` instead.

A module can implement its own version of the de-serializer, for example, the below will register a de-serializer that will tell RMB to set a User to not active if the expiration date has passed. This will be run when a User JSON is passed in as part of a request

```java
ObjectMapperTool.registerDeserializer(User.class, new UserDeserializer());
Expand Down
16 changes: 15 additions & 1 deletion dbschema/src/main/java/org/folio/dbschema/ObjectMapperTool.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public static <M, D extends JsonDeserializer<M>> void registerDeserializer(Class
}

/**
* Map JSON to type.
* Map (deserialize) JSON String to java type instance.
*
* @param content JSON content
* @param valueType Resulting type.
Expand All @@ -57,6 +57,20 @@ public static <T> T readValue(String content, Class<T> valueType) {
}
}

/**
* Map (serialize) java type instance to JSON String.
*
* @param o java class value
* @return serialized JSON String
*/
public static <T> String valueAsString(T o) {
try {
return getMapper().writeValueAsString(o);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}

private static ObjectMapper createDefaultMapper() {
var module = new SimpleModule();
module.addSerializer(Date.class, new DateSerializer(Date.class));
Expand Down
32 changes: 20 additions & 12 deletions dbschema/src/test/java/org/folio/dbschema/ObjectMapperToolTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,18 @@
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;

import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import java.io.UncheckedIOException;
import java.time.Instant;
import java.util.Date;

import org.folio.okapi.testing.UtilityClassTester;
import org.folio.util.ResourceUtil;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;

class ObjectMapperToolTest {

@Test
Expand All @@ -42,9 +40,9 @@ void testReadValueException() {
}

@Test
void canReadSchema() throws Throwable {
void canReadSchema() {
String dbJson = ResourceUtil.asString("schema.json");
Schema dbSchema = ObjectMapperTool.getMapper().readValue(dbJson, Schema.class);
Schema dbSchema = ObjectMapperTool.readValue(dbJson, Schema.class);
assertThat(dbSchema.getTables().get(0).getTableName(), is("item"));
assertThat(dbSchema.getTables().get(0).getLikeIndex().get(0)
.getArraySubfield(), is("name"));
Expand Down Expand Up @@ -81,10 +79,10 @@ void canReadSchema() throws Throwable {
"+0000-01-01T00:00:00.000+00:00, 0000-01-01T00:00:00.000+00:00",
"+0000-12-31T23:59:59.999+00:00, 0000-12-31T23:59:59.999+00:00",
})
void date(String input, String expected) throws Exception {
void date(String input, String expected) {
var json = '"' + input + '"';
var date = ObjectMapperTool.readValue(json, Date.class);
var json2 = ObjectMapperTool.getMapper().writeValueAsString(date);
var json2 = ObjectMapperTool.valueAsString(date);
assertThat(json2, is('"' + expected + '"'));
}

Expand All @@ -95,10 +93,10 @@ void date(String input, String expected) throws Exception {
" 1, 1970-01-01T00:00:00.001+00:00",
"1800000000000, 2027-01-15T08:00:00.000+00:00",
})
void date(long input, String expected) throws Exception {
void date(long input, String expected) {
var date = ObjectMapperTool.readValue("" + input, Date.class);
assertThat(date, is(new Date(input)));
var json = ObjectMapperTool.getMapper().writeValueAsString(date);
var json = ObjectMapperTool.valueAsString(date);
assertThat(json, is('"' + expected + '"'));
}

Expand All @@ -108,12 +106,12 @@ static class Foo {
}

@Test
void foo() throws JsonProcessingException {
void foo() {
var json = "{\"s\":\"a\",\"dueDate\":\"+1970-01-01T00:00:00.000+00:00\"}";
var foo = ObjectMapperTool.readValue(json, Foo.class);
assertThat(foo.s, is("a"));
assertThat(foo.dueDate.toInstant(), is(Instant.parse("1970-01-01T00:00:00.000+00:00")));
var json2 = ObjectMapperTool.getMapper().writeValueAsString(foo);
var json2 = ObjectMapperTool.valueAsString(foo);
var expected = json.replace("+1970", "1970");
assertThat(json2, is(expected));
}
Expand All @@ -126,4 +124,14 @@ void fooException() {
assertThat(e.getMessage(), containsString("Foo[\"dueDate\"]"));
assertThat(e.getCause(), instanceOf(MismatchedInputException.class));
}

static class EmptyBean {
}

@Test
void valueAsStringException() {
var emptyBean = new EmptyBean();
var e = assertThrows(UncheckedIOException.class, () -> ObjectMapperTool.valueAsString(emptyBean));
assertThat(e.getCause(), instanceOf(InvalidDefinitionException.class));
}
}
12 changes: 12 additions & 0 deletions doc/upgrading.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ These are notes to assist upgrading to newer versions.
See the [NEWS](../NEWS.md) summary of changes for each version.

<!-- ../../okapi/doc/md2toc -l 2 -h 3 upgrading.md -->
* [Version 35.3](#version-353)
* [Version 35.2](#version-352)
* [Version 35.1](#version-351)
* [Version 35.0](#version-350)
Expand All @@ -25,6 +26,12 @@ See the [NEWS](../NEWS.md) summary of changes for each version.
* [Version 25](#version-25)
* [Version 20](#version-20)

## Version 35.3

Don't use `JsonObject.mapFrom` to serialize a Java class instance to JSON,
RMB's database methods automatically do this. When writing custom SQL use
`ObjectMapperTool.valueAsString` to serialize in a way compatible with RMB's deserializer.

## Version 35.2

35.2.\* is the Quesnelia (R1 2024) version.
Expand All @@ -47,6 +54,11 @@ because the
and [artifact name](https://github.com/jakartaee/validation/commit/80f3223c3aa7696e3a732ae802baac8fc529f785)
have changed.

Don't use `JsonObject.mapFrom` to serialize a Java class instance to JSON,
RMB's database methods automatically do this. When writing custom SQL use
`ObjectMapperTool.getMapper().writeValueAsString` to serialize
in a way compatible with RMB's deserializer.

## Version 35.1

35.1.\* is the Poppy (R2 2023) version.
Expand Down

0 comments on commit 2fded21

Please sign in to comment.