All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.afrozaar.wordpress.wpapi.v2.response.CustomRenderableParser Maven / Gradle / Ivy

There is a newer version: 4.8.3
Show newest version
package com.afrozaar.wordpress.wpapi.v2.response;

import static java.util.Optional.ofNullable;

import com.afrozaar.wordpress.wpapi.v2.model.DeleteResponse;
import com.afrozaar.wordpress.wpapi.v2.model.Media;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.HttpClientErrorException;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
 * Utility class that is able to handle the recent change where WP 4.7 now has {@code raw} and {@code rendered} fields for some display fields.
 * 

* This class is temporary for the purpose of transitioning between 4.6 and 4.7. */ public final class CustomRenderableParser { private static final Logger LOG = LoggerFactory.getLogger(CustomRenderableParser.class); public static final String FIELD_PREVIOUS = "previous"; public static final String FIELD_DELETED = "deleted"; private static ObjectMapper objectMapper = new ObjectMapper(); private static final Set modifiableFields = new HashSet<>(Arrays.asList("description", "caption")); private static final String RENDERED = "rendered"; private static final String RAW = "raw"; private CustomRenderableParser() { // Make other classes unable to instantiate. } public static Media parseMedia(String stringResponse) throws HttpClientErrorException { return parse(stringResponse, Media.class); } public static T parse(ResponseEntity response, Class clazz) { return parse(response.getBody(), clazz); } public static T parse(String response, Class clazz) { LOG.debug("Parsing response for {}", clazz.getCanonicalName()); LOG.trace("Type parameters: {}", Arrays.asList(clazz.getTypeParameters())); LOG.trace("Response String: {}", response); try { final JsonNode jsonNode = objectMapper.readValue(response, JsonNode.class); return parseNode(jsonNode, clazz); } catch (IOException e) { LOG.error("Error ", e); throw new HttpClientErrorException(HttpStatus.I_AM_A_TEAPOT, "There was an error parsing the response body.", response.getBytes(), StandardCharsets.UTF_8); } } public static DeleteResponse parseDeleteResponse(ResponseEntity response, Class clazz) { return parseDeleteResponse(response.getBody(), clazz); } public static DeleteResponse parseDeleteResponse(String response, Class clazz) { LOG.trace("parsing delete response for '{}' from {}", clazz.getCanonicalName(), response); // 4.6 responds with the object JSON only. // 4.7 responds with JSON that has a 'deleted' and 'previous' field. The previous is what the JSON-only response was for 4.6. Function> resolveFor4_7 = node -> DeleteResponse.of(node.get(FIELD_DELETED).asBoolean(), parseNode(node.get(FIELD_PREVIOUS), clazz)); Function> resolveFor4_6 = node -> DeleteResponse.of(true, parseNode(node, clazz)); try { final JsonNode rootNode = objectMapper.readValue(response, JsonNode.class); return ofNullable(rootNode.get(FIELD_DELETED)) .map(jsonNode -> resolveFor4_7) .orElse(resolveFor4_6) .apply(rootNode); } catch (IOException e) { LOG.error("Error ", e); throw new HttpClientErrorException(HttpStatus.I_AM_A_TEAPOT, "There was an error reading the response body.", response.getBytes(), StandardCharsets.UTF_8); } } private static T parseNode(JsonNode jsonNode, Class clazz) { LOG.trace("{} isArray: {}", clazz.getCanonicalName(), clazz.isArray()); if (clazz.isArray()) { jsonNode.iterator().forEachRemaining(transformNode); } else { transformNode.accept(jsonNode); } return objectMapper.convertValue(jsonNode, clazz); } private static final Function>, Stream>> streamIterator = iterator -> StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false); private static final Function> findRenderableFields = jsonNode -> streamIterator.apply(jsonNode.fields()) .filter(entry -> entry.getValue().fields().hasNext()) .filter(entry -> streamIterator.apply(entry.getValue().fields()) .filter(field -> RAW.equals(field.getKey()) || RENDERED.equals(field.getKey())) .count() > 0) .map(Map.Entry::getKey); private static final Consumer transformNode = node -> findRenderableFields.apply(node) .filter(modifiableFields::contains) .forEach(renderableField -> { final Optional raw1 = ofNullable(node.get(renderableField).get(RAW)); if (raw1.isPresent()) { final JsonNode jsonNode = raw1.get(); ((ObjectNode) node).put(renderableField, jsonNode.asText()); } else { ofNullable(node.get(renderableField).get(RENDERED)) .map(jsonNode -> jsonNode.asText().replaceAll("<[^>]*>", "")) .map(strippedText -> { LOG.warn("Raw field for parent '{}' not available. Using regex-stripped value: {}", renderableField, strippedText); return strippedText; }) .ifPresent(strippedText -> ((ObjectNode) node).put(renderableField, strippedText)); } }); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy