/**
* Copyright (c) 2009 - 2016 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
* version 2 (GPLv2). There is NO WARRANTY for this software, express or
* implied, including the implied warranties of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
* along with this software; if not, see
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* Red Hat trademarks are not licensed under GPLv2. No permission is
* granted to use or replicate Red Hat trademarks that are incorporated
* in this software or its documentation.
*/
package org.candlepin.jackson;
import org.candlepin.common.exceptions.CandlepinJsonProcessingException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;
/**
* The CandlepinAttributeDeserializer handles the deserialization of attributes, processing both
* the current attribute mapping style and obsoleted formats.
*/
public class CandlepinAttributeDeserializer extends StdDeserializer<Map<String, String>> {
private static Logger log = LoggerFactory.getLogger(CandlepinAttributeDeserializer.class);
public CandlepinAttributeDeserializer() {
this(null);
}
public CandlepinAttributeDeserializer(Class<?> valueClass) {
super(valueClass);
}
@Override
public Map<String, String> deserialize(JsonParser parser, DeserializationContext context)
throws IOException, JsonProcessingException {
Map<String, String> output = new HashMap<String, String>();
TreeNode node = parser.readValueAsTree();
if (node.isObject()) {
log.debug("Processing attributes as a mapping of key/value pairs");
// This is what we want, key/value pairs (hopefully).
for (Iterator<String> fieldNames = node.fieldNames(); fieldNames.hasNext();) {
String field = fieldNames.next();
TreeNode valueNode = node.get(field);
if (!valueNode.isValueNode()) {
throw new CandlepinJsonProcessingException(
"Unexpected value type in map: " + valueNode.asToken(),
parser.getCurrentLocation()
);
}
JsonParser subparser = valueNode.traverse();
subparser.nextValue();
String value = subparser.getValueAsString();
subparser.close();
log.debug("Found key/value pair: {} = {}", field, value);
output.put(field, value);
}
}
else if (node.isArray()) {
log.debug("Processing attributes as an array of attribute objects");
// Probably old collection of objects containing name/value attribute.
// Iterate over the objects, adding the values to the map.
int size = node.size();
for (int i = 0; i < size; ++i) {
TreeNode obj = node.get(i);
if (!obj.isObject()) {
throw new CandlepinJsonProcessingException(
"Unexpected value type in array: " + obj.asToken(),
parser.getCurrentLocation()
);
}
TreeNode fieldNode = obj.get("name");
if (fieldNode == null) {
throw new CandlepinJsonProcessingException(
"No attribute name defined in attribute object",
parser.getCurrentLocation()
);
}
if (!fieldNode.isValueNode()) {
throw new CandlepinJsonProcessingException(
"Unexpected value type for attribute name: " + fieldNode.asToken(),
parser.getCurrentLocation()
);
}
JsonParser subparser = fieldNode.traverse();
subparser.nextValue();
String field = subparser.getValueAsString();
subparser.close();
TreeNode valueNode = obj.get("value");
if (valueNode != null) {
if (!valueNode.isValueNode()) {
throw new CandlepinJsonProcessingException(
"Unexpected value type for attribute value: " + valueNode.asToken(),
parser.getCurrentLocation()
);
}
subparser = valueNode.traverse();
subparser.nextValue();
String value = subparser.getValueAsString();
subparser.close();
log.debug("Found key/value pair: {} = {}", field, value);
output.put(field, value);
}
else {
log.debug("Found key/value pair: {} = {}", field, null);
output.put(field, null);
}
}
}
else {
log.debug("Processing attributes as an array of attribute objects");
// Uh oh.
throw new CandlepinJsonProcessingException(
"Unexpected attribute value type: " + node.asToken(),
parser.getCurrentLocation()
);
}
return output;
}
}