Skip to content

Commit

Permalink
🚧 Added general JSON Key / value extractor until a better filter / in…
Browse files Browse the repository at this point in the history
…terceptor pattern can be done.
  • Loading branch information
adarro committed Aug 24, 2024
1 parent 114c082 commit 34a47e9
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package io.truthencode.dal.general;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
Expand Down Expand Up @@ -107,75 +105,61 @@ public Uni<Response> create(Feat Feat) {
.replaceWith(Response.ok(Feat).status(CREATED)::build);
}

@KeyExtracting
@PUT
@Path("{id}")
@Consumes(value = {MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON})
public Uni<Response> updateFromRaw(Long id, String body) {
public Uni<Response> updateFromRaw(Long id, String body, @HeaderParam(value = UPDATE_KEYS_HEADER) String header) {
// Response.ResponseBuilder builder = null;

Log.warn("@KeyExtracting updateFromRaw: " + body);
Log.warn("@KeyExtracting updateFromRaw: header " + header);
return Panache
.withTransaction(() -> Feat.<Feat>findById(id)
.onItem().ifNotNull().invoke(entity -> {
ObjectMapper mapper = new ObjectMapper();
JsonFactory factory = mapper.getFactory();
try {
Log.warn("analyzing body: " + body);
JsonNode root = mapper.readTree(factory.createParser(body));
ObjectNode rootNode = (ObjectNode) root;
var keys = new HashSet<String>();
rootNode.fieldNames().forEachRemaining(keys::add);
var kMap = JSONSupport.extractKeys(body, header);
var keys = kMap.keys();
var rootNode = kMap.node();

if (keys.isEmpty()) {
throw new WebApplicationException("Field keys were not set on request. Please specify update fields by Header, Query parameters", 422);
throw new WebApplicationException("Field keys were not set on request and could not determine fields to update. Please specify update fields by Header, Query parameters", 422);
}
/* Need to go field by field to check for change on required.
How do we know if nullable / optional fields are set?
If not supplied in JSON, they are defaulted to null in the Feat object.
If supplied in JSON, but set to null, then it is set, and we want to update.
However, both options are identical at this point in the code as the JSON has been automatically mapped to the Feat object.
So, we then need to generate all missing fields to existing values prior to calling this method.
*/
Log.warn("Attempting to update Feat with id: " + id + "using requested keys: " + keys);
Log.warn("Attempting to update Feat with id: " + id + " using requested keys: " + keys);
keys.stream()
.map(String::toLowerCase)
.map(String::trim)
.forEach(fieldKey -> {
Log.warn("Updating field [" + fieldKey + "]");
switch (fieldKey) {
case "id":
// Log.warn("Matched field [id]");
// We don't want to update the id. Should either error or ignore.
Log.warn("ID field can not be changed.");
break;
case "name":
Log.info("Matched field [name]");
Log.warn("Mapping name: " + rootNode.findValues(fieldKey).stream().findFirst().get().asText());
entity.name = rootNode.findValues(fieldKey).stream().findFirst().get().asText();

break;
case "description":
Log.info("Matched field [description]");
entity.description = rootNode.findValues(fieldKey).stream().findFirst().isPresent() ? rootNode.findValues(fieldKey).stream().findFirst().get().asText() : null;
entity.description = rootNode.findValues(fieldKey).stream().findFirst().map(JsonNode::asText).orElse(null);
break;
case "usages":
Log.info("Matched field [usages]");
if (rootNode.findValues(fieldKey).stream().findFirst().isPresent()) {

entity.usages = new HashSet<>();
rootNode.findValue(fieldKey).forEach(j -> {
Log.warn("Adding usage -> " + j);
entity.usages.add(Usage.valueOf(j.asText()));
});
// Do we warn if the usage is not found?
}
break;
default:
Log.warn("Field [" + fieldKey + "] is not mapped or does not exist. Corresponding value will not be updated.");
}
});
// Validate the Feat before allowing a commit.
featService.validateFeat(entity);
} catch (IOException e) {
throw new RuntimeException(e);
throw new RuntimeException("Error processing JSON", e);
}
})
)
Expand Down Expand Up @@ -206,7 +190,7 @@ public Uni<Response> updateFromRaw(
throw new WebApplicationException("Feat name was not set on request.", 422);
}

Log.warn("Attempting to update Feat with id: " + id);
Log.warn("Attempting to update raw/ Feat with id: " + id);
return Panache
.withTransaction(() -> PanacheEntityBase.<Feat>findById(id)
.onItem().ifNotNull().invoke(entity -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,43 @@ static Set<String> getKeys(String... updateKeys) {
return keys;
}

static Set<String> extractKeys(String jsonData) {
static Set<String> extractKeys(String jsonData) throws IOException {
Set<String> keys = new HashSet<>();
ObjectMapper mapper = new ObjectMapper();
JsonFactory factory = mapper.getFactory();
JsonParser jp = null;
try {
Log.warn("analyzing body: " + jsonData);
jp = factory.createParser(jsonData);
JsonNode root = mapper.readTree(jp);
ObjectNode rootNode = (ObjectNode) root;

rootNode.fieldNames().forEachRemaining(keys::add);
} catch (IOException e) {
throw new RuntimeException(e);
}
Log.warn("analyzing body: " + jsonData);
JsonParser jp = factory.createParser(jsonData);
JsonNode root = mapper.readTree(jp);
ObjectNode rootNode = (ObjectNode) root;

rootNode.fieldNames().forEachRemaining(keys::add);

return keys;
}

/**
* Extracts explicitly named key values from keylists or extracts JSON fields from the request body and adds the keys
*
* @param jsonData JSON data for updates
* @param keyLists possible lists of keys to extract. I.e. an array containing some Header, query-string parameters, etc.
* @return a KeyedJsonNode containing the keys and a JSON node containing the JSoN data.
* @throws IOException
*/
static KeyedJsonNode extractKeys(String jsonData, String... keyLists) throws IOException {

Set<String> keys = (keyLists != null) ? getKeys(keyLists) : new HashSet<>();
ObjectMapper mapper = new ObjectMapper();
JsonFactory factory = mapper.getFactory();
Log.warn("analyzing body: " + jsonData);
JsonParser jp = factory.createParser(jsonData);
JsonNode root = mapper.readTree(jp);
ObjectNode rootNode = (ObjectNode) root;
if (keys.isEmpty())
rootNode.fieldNames().forEachRemaining(keys::add);
return new KeyedJsonNode(rootNode, keys);

}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.truthencode.dal.general;

import com.fasterxml.jackson.databind.node.ObjectNode;

import java.util.Set;

public record KeyedJsonNode(ObjectNode node, Set<String> keys) {
}

0 comments on commit 34a47e9

Please sign in to comment.