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}