001/*
002 * This file is part of the JDrupes JSON utilities project.
003 * Copyright (C) 2017  Michael N. Lipp
004 *
005 * This program is free software; you can redistribute it and/or modify it 
006 * under the terms of the GNU Lesser General Public License as published
007 * by the Free Software Foundation; either version 3 of the License, or 
008 * (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful, but 
011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
013 * License for more details.
014 *
015 * You should have received a copy of the GNU Lesser General Public License along 
016 * with this program; if not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jdrupes.json;
020
021import com.fasterxml.jackson.core.JsonFactory;
022
023import java.beans.BeanInfo;
024import java.beans.IntrospectionException;
025import java.beans.Introspector;
026import java.beans.PropertyEditor;
027import java.beans.PropertyEditorManager;
028import java.util.Collections;
029import java.util.Map;
030import java.util.WeakHashMap;
031
032/**
033 * The base class for the {@link JsonBeanEncoder} and {@link JsonBeanDecoder}.
034 */
035public abstract class JsonCodec {
036
037        private static JsonFactory defaultFactory = new JsonFactory();
038        
039        protected static JsonFactory defaultFactory() {
040                return defaultFactory;
041        }
042
043        private static final Map<Class<?>,PropertyEditor> propertyEditorCache
044                = Collections.synchronizedMap(new WeakHashMap<>());
045        
046        protected static PropertyEditor findPropertyEditor(Class<?> cls) {
047                PropertyEditor propertyEditor = propertyEditorCache.get(cls);
048                if (propertyEditor == null && !propertyEditorCache.containsKey(cls)) {
049                        // Never looked for before.
050                        propertyEditor = PropertyEditorManager.findEditor(cls);
051                        propertyEditorCache.put(cls, propertyEditor);
052                }
053                return propertyEditor;
054        }
055        
056        private static final Map<Class<?>,BeanInfo> beanInfoCache
057                = Collections.synchronizedMap(new WeakHashMap<>());
058
059        protected static BeanInfo findBeanInfo(Class<?> cls) {
060                BeanInfo beanInfo = beanInfoCache.get(cls);
061                if (beanInfo == null && !beanInfoCache.containsKey(cls)) {
062                        try {
063                                beanInfo = Introspector.getBeanInfo(cls, Object.class);
064                        } catch (IntrospectionException e) {
065                                // Bad luck
066                        }
067                        beanInfoCache.put(cls, beanInfo);
068                }
069                return beanInfo;
070        }
071        
072        /**
073         * The encoder and decoder make use of the information from
074         * {@link PropertyEditorManager#findEditor(Class)} and
075         * {@link Introspector#getBeanInfo(Class, Class)}. You'd
076         * expect these methods to provide some caching to speed
077         * up requests for the same infomration, but they don't.
078         * 
079         * The results are therefore kept in an internal cache.
080         * This cache may, however, become outdated of additional
081         * classes are loaded into the VM dynamically. This method
082         * can be used to clear the caches if this is required. 
083         */
084        public static void clearCaches() {
085                propertyEditorCache.clear();
086                beanInfoCache.clear();
087        }
088        
089        /**
090         * Add an alias for the given class. If defined, the alias
091         * will be used instead of the class name by the encoder.
092         * 
093         * @param clazz the class
094         * @param alias the alias
095         * @return the object for easy chaining
096         */
097        public abstract JsonCodec addAlias(Class<?> clazz, String alias);
098        
099}