/** * The contents of this file are subject to the OpenMRS Public License * Version 1.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://license.openmrs.org * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * Copyright (C) OpenMRS, LLC. All Rights Reserved. */ package org.openmrs.module.sync.serialization; import java.util.HashMap; import java.util.Map; import org.openmrs.module.sync.SyncUtil; /** * Serializes and de-serializes Map<K,V> where K and V are types we can otherwise normalize. The * serialization format is as follows: {{key||value}}{{key||value}} */ public class MapNormalizer extends Normalizer { /*** * Returns string representation of map object. If o is not an instance of map, null is * returned. If map.size() == 0 empty string is returned. For the serialization format see class * comments. */ public String toString(Object o) { Normalizer keyNormalizer = null; Normalizer valueNormalizer = null; StringBuilder sb = new StringBuilder(); //check to see if it is not null and map if (o != null && Map.class.isAssignableFrom(o.getClass())) { Map m = (Map) o; if (m.size() == 0) { return ""; } else { //figure out what we are dealing with here keyNormalizer = SyncUtil.getNormalizer(m.keySet().toArray()[0].getClass()); valueNormalizer = SyncUtil.getNormalizer(m.get(m.keySet().toArray()[0]).getClass()); if (keyNormalizer != null && valueNormalizer != null) { for (Object key : m.keySet()) { sb.append("{{"); sb.append(keyNormalizer.toString(key)); sb.append("||"); //sb.append("</key>"); //sb.append("<value>"); sb.append(valueNormalizer.toString(m.get(key))); sb.append("}}"); //sb.append("</value>"); } } return sb.toString(); } } return null; } /*** * De-serializes state back into map object. For serialization format see class comments. If * clazz not Map null returned. If s null, null returned. If s empty, empty Map object returned. * If non-empty string passed in but format does not conform IllegalArgumentException thrown. */ public Object fromString(Class clazz, String s) throws IllegalArgumentException { Map map = new HashMap(); if (!Map.class.isAssignableFrom(clazz) || s == null) { return null; } //if it is empty string return empty map if (s.length() == 0) { return map; } // strip leading and closing {{ }} since we're splitting it if (!s.startsWith("{{") || s.lastIndexOf("}}") < 3) { //this isn't right, we are expecting {{k,v}}||{{k,v}}... throw new IllegalArgumentException( "Invalid serialization format for map object. {{key||value}}{{key||value}} expected."); } String tmp = s; tmp = tmp.replaceFirst("\\{\\{", ""); tmp = tmp.substring(0, tmp.lastIndexOf("}}")); for (String entry : tmp.split("\\}\\}\\{\\{")) { //entry = entry.trim(); // take out whitespace if (entry.contains("||")) { String keyvalArray[] = entry.split("\\|\\|"); // try to convert to a simple object Object tmpKey = SyncUtil.convertStringToObject(keyvalArray[0], String.class); if (tmpKey == null) throw new IllegalArgumentException("cannot deserialize the 'key' from map entry: " + entry); // we could have empty values Object tmpValue = ""; // since we're converting everything to strings, this is effectively 'null' if (keyvalArray.length > 1) tmpValue = SyncUtil.convertStringToObject(keyvalArray[1], String.class); if (tmpValue == null) throw new IllegalArgumentException("cannot deserialize the 'value' from map entry: " + entry); map.put(tmpKey, tmpValue); } else { throw new IllegalArgumentException( "Invalid serialization format for map entry. {{key||value}} expected. encountered:" + entry); } } return map; } }