Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.unomi.persistence.spi; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonTokenId; import com.fasterxml.jackson.core.ObjectCodec; import com.fasterxml.jackson.core.TreeNode; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer; import com.fasterxml.jackson.databind.node.ObjectNode; import java.io.IOException; import java.util.*; /** * This Jackson deserializer makes it possible to register field matching * regular expressions that can be matched to class names, as in the following * example: * * SimpleModule deserializerModule = * new SimpleModule("PropertyTypedObjectDeserializerModule", * new Version(1, 0, 0, null, "org.apache.unomi.rest", "deserializer")); * PropertyTypedObjectDeserializer propertyTypedObjectDeserializer = new PropertyTypedObjectDeserializer(); * propertyTypedObjectDeserializer.registerMapping("type=.*Condition", Condition.class); * deserializerModule.addDeserializer(Object.class, propertyTypedObjectDeserializer); * objectMapper.registerModule(deserializerModule); * * In this example any JSON object that has a "type" property that matches the * ".*Condition" regular expression will be parsed and mapped to a Condition class * * Note that there exists a way to map properties as type identifiers in Jackson, * but this feature is very limited and requires hardcoding possible values. * This deserializer is much more flexible and powerful. */ public class PropertyTypedObjectDeserializer extends UntypedObjectDeserializer { private static final long serialVersionUID = -2561171359946902967L; private Map<String, Class<? extends Object>> registry = new LinkedHashMap<String, Class<? extends Object>>(); private Map<String, Set<String>> fieldValuesToMatch = new LinkedHashMap<String, Set<String>>(); public void registerMapping(String matchExpression, Class<? extends Object> mappedClass) { registry.put(matchExpression, mappedClass); String[] fieldParts = matchExpression.split("="); Set<String> valuesToMatch = fieldValuesToMatch.get(fieldParts[0]); if (valuesToMatch == null) { valuesToMatch = new LinkedHashSet<String>(); } valuesToMatch.add(fieldParts[1]); fieldValuesToMatch.put(fieldParts[0], valuesToMatch); } @Override public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { if (jp.getCurrentTokenId() != JsonTokenId.ID_START_OBJECT) { return super.deserialize(jp, ctxt); } ObjectCodec codec = jp.getCodec(); TreeNode treeNode = codec.readTree(jp); Class<? extends Object> objectClass = null; if (treeNode instanceof ObjectNode) { ObjectNode root = (ObjectNode) treeNode; Iterator<Map.Entry<String, JsonNode>> elementsIterator = root.fields(); while (elementsIterator.hasNext()) { Map.Entry<String, JsonNode> element = elementsIterator.next(); String name = element.getKey(); if (fieldValuesToMatch.containsKey(name)) { Set<String> valuesToMatch = fieldValuesToMatch.get(name); for (String valueToMatch : valuesToMatch) { if (element.getValue().asText().matches(valueToMatch)) { objectClass = registry.get(name + "=" + valueToMatch); break; } } if (objectClass != null) { break; } } } if (objectClass == null) { objectClass = HashMap.class; } } else { } if (objectClass == null) { return super.deserialize(codec.treeAsTokens(treeNode), ctxt); } return codec.treeToValue(treeNode, objectClass); } }