Skip to content

Commit

Permalink
Fix operation and operation code deserialization (#3012)
Browse files Browse the repository at this point in the history
Co-authored-by: Aaron Klish <aklish@gmail.com>
  • Loading branch information
justin-tay and aklish committed Jun 17, 2023
1 parent e4e77be commit 8ac2ca5
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,7 @@ public static Supplier<Pair<Integer, JsonNode>> processAtomicOperations(DataStor
Operations operations = requestScope.getMapper().forAtomicOperations().readDoc(operationsDoc);
actions = operations.getOperations();
} catch (InvalidFormatException e) {
if (e.getMessage() != null
&& e.getMessage().contains("$OperationCode")) {
if (OperationCode.class.equals(e.getTargetType())) {
// Invalid op code results in a format error as it is an enum
throw new InvalidEntityBodyException(
"Invalid Atomic Operations extension operation code:"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;

import java.io.IOException;
import java.util.Locale;

/**
* The JSON Atomic Operation extension entity body.
Expand Down Expand Up @@ -58,6 +62,15 @@ public String getName() {
public int getId() {
return this.id;
}

@JsonCreator
public static OperationCode fromName(String name) throws IOException {
try {
return name != null ? OperationCode.valueOf(name.toUpperCase(Locale.ENGLISH)) : null;
} catch (RuntimeException e) {
throw InvalidFormatException.from(null, e.getMessage(), name, OperationCode.class);
}
}
}

private final OperationCode operationCode;
Expand Down
17 changes: 17 additions & 0 deletions elide-core/src/main/java/com/yahoo/elide/jsonapi/models/Patch.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;

import java.io.IOException;
import java.util.Locale;

/**
* POJO which represents a JSON API patch extension entity body.
Expand Down Expand Up @@ -51,6 +55,19 @@ public enum Operation {
public String getName() {
return name;
}

public int getId() {
return this.id;
}

@JsonCreator
public static Operation fromName(String name) throws IOException {
try {
return name != null ? Operation.valueOf(name.toUpperCase(Locale.ENGLISH)) : null;
} catch (RuntimeException e) {
throw InvalidFormatException.from(null, e.getMessage(), name, Operation.class);
}
}
}

private final Operation operation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;

Expand Down Expand Up @@ -47,4 +48,25 @@ void readSingle() throws JsonProcessingException {
Resource resource = objectMapper.treeToValue(operation.getData(), Resource.class);
assertEquals("articles", resource.getType());
}

@Test
void readSingleReadEnumsUsingToString() throws JsonProcessingException {
String json = """
{
"op": "update",
"data": {
"type": "articles",
"id": "13",
"attributes": {
"title": "To TDD or Not"
}
}
}
""";
ObjectMapper objectMapper = new ObjectMapper().enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
Operation operation = objectMapper.readValue(json, Operation.class);
assertEquals(Operation.OperationCode.UPDATE, operation.getOperationCode());
Resource resource = objectMapper.treeToValue(operation.getData(), Resource.class);
assertEquals("articles", resource.getType());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,18 @@
import static org.junit.jupiter.api.Assertions.assertEquals;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import org.junit.jupiter.api.Test;

import java.util.Collections;
import java.util.List;

public class PatchTest {
class PatchTest {
@Test
public void testSerialization() throws Exception {
void testSerialization() throws Exception {
ObjectMapper mapper = new ObjectMapper();
JsonNode valueNode = mapper.readTree("\"stringValue\"");
Patch patch = new Patch(Patch.Operation.ADD, "/foo/bar", valueNode);
Expand All @@ -29,7 +31,7 @@ public void testSerialization() throws Exception {
}

@Test
public void testDeserialization() throws Exception {
void testDeserialization() throws Exception {
ObjectMapper mapper = new ObjectMapper();
String input = "{\"op\":\"add\",\"path\":\"/foo/bar\",\"value\":\"stringValue\"}";
Patch patch = mapper.readValue(input, Patch.class);
Expand All @@ -45,7 +47,7 @@ public void testDeserialization() throws Exception {
}

@Test
public void testListSerialization() throws Exception {
void testListSerialization() throws Exception {
ObjectMapper mapper = new ObjectMapper();
JsonNode valueNode = mapper.readTree("\"stringValue\"");
List<Patch> patches = Collections.singletonList(new Patch(Patch.Operation.ADD, "/foo/bar", valueNode));
Expand All @@ -57,7 +59,7 @@ public void testListSerialization() throws Exception {
}

@Test
public void testListDeserialization() throws Exception {
void testListDeserialization() throws Exception {
ObjectMapper mapper = new ObjectMapper();

String input = "[{\"op\":\"add\",\"path\":\"/foo/bar\",\"value\":\"stringValue\"}]";
Expand All @@ -72,4 +74,20 @@ public void testListDeserialization() throws Exception {

assertEquals("stringValue", value, "Deserialized patch value should match");
}

@Test
void testDeserializationReadEnumsUsingToString() throws Exception {
ObjectMapper mapper = new ObjectMapper().enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
String input = "{\"op\":\"add\",\"path\":\"/foo/bar\",\"value\":\"stringValue\"}";
Patch patch = mapper.readValue(input, Patch.class);

assertEquals(Patch.Operation.ADD, patch.getOperation(), "Deserialized patch operation should match.");
assertEquals("/foo/bar", patch.getPath(), "Deserialized patch path should match.");

JsonNode node = patch.getValue();

String value = mapper.treeToValue(node, String.class);

assertEquals("stringValue", value, "Deserialized patch value should match");
}
}

0 comments on commit 8ac2ca5

Please sign in to comment.