001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau; 018 019import static org.apache.juneau.commons.utils.CollectionUtils.*; 020import static org.apache.juneau.commons.utils.ThrowableUtils.*; 021import static org.apache.juneau.commons.utils.Utils.*; 022 023import java.lang.reflect.*; 024import java.util.*; 025 026import org.apache.juneau.annotation.*; 027 028/** 029 * Represents a map of dictionary type names to bean classes that make up a bean dictionary. 030 * 031 * <p> 032 * In general, this approach for defining dictionary names for classes is used when it's not possible to use the 033 * {@link Bean#typeName() @Bean(typeName)} annotation. 034 * 035 * <h5 class='section'>Example:</h5> 036 * <p class='bjava'> 037 * <jc>// A bean dictionary map consisting of classes without @Bean(typeName) annotations</jc> 038 * <jc>// that require type names to be explicitly specified.</jc> 039 * <jk>public class</jk> MyBeanDictionaryMap <jk>extends</jk> BeanDictionaryMap { 040 * 041 * <jc>// Must provide a no-arg constructor!</jc> 042 * <jk>public</jk> MyBeanDictionaryMap() { 043 * append(<js>"MyBean"</js>, MyBean.<jk>class</jk>); 044 * append(<js>"MyBeanArray"</js>, MyBean[].<jk>class</jk>); 045 * append(<js>"StringArray"</js>, String[].<jk>class</jk>); 046 * append(<js>"String2dArray"</js>, String[][].<jk>class</jk>); 047 * append(<js>"IntArray"</js>, <jk>int</jk>[].<jk>class</jk>); 048 * append(<js>"Int2dArray"</js>, <jk>int</jk>[][].<jk>class</jk>); 049 * append(<js>"LinkedList"</js>, LinkedList.<jk>class</jk>); 050 * append(<js>"TreeMap"</js>, TreeMap.<jk>class</jk>); 051 * append(<js>"LinkedListOfInts"</js>, LinkedList.<jk>class</jk>, Integer.<jk>class</jk>); 052 * append(<js>"LinkedListOfR1"</js>, LinkedList.<jk>class</jk>, R1.<jk>class</jk>); 053 * append(<js>"LinkedListOfCalendar"</js>, LinkedList.<jk>class</jk>, Calendar.<jk>class</jk>); 054 * } 055 * } 056 * 057 * <jc>// Use it in a parser.</jc> 058 * ReaderParser <jv>parser</jv> = JsonParser 059 * .<jsm>create</jsm>() 060 * .dictionary(MyBeanDictionaryMap.<jk>class</jk>) 061 * .build(); 062 * </p> 063 * 064 * <p> 065 * Subclasses must implement a public no-arg constructor so that it can be instantiated by the bean context code. 066 * 067 * 068 * @serial exclude 069 */ 070@SuppressWarnings("rawtypes") 071public class BeanDictionaryMap extends LinkedHashMap<String,Object> { 072 private static final long serialVersionUID = 1L; 073 074 /** 075 * Constructor. 076 */ 077 protected BeanDictionaryMap() {} 078 079 private void assertValidParameter(Object o) { 080 if (nn(o)) { 081 if (o instanceof Class) 082 return; 083 if (isArray(o)) { 084 for (var i = 0; i < Array.getLength(o); i++) 085 assertValidParameter(Array.get(o, i)); 086 return; 087 } 088 } 089 throw bex("Invalid object type passed to BeanDictionaryMap: ''{0}''. Only objects of type Class or Object[] containing Class or Object[] objects can be used.", cn(o)); 090 } 091 092 /** 093 * Add a dictionary name mapping for the specified class. 094 * 095 * @param typeName The dictionary name of the class. 096 * @param c The class represented by the dictionary name. 097 * @return This object. 098 */ 099 protected BeanDictionaryMap append(String typeName, Class<?> c) { 100 put(typeName, c); 101 return this; 102 } 103 104 /** 105 * Add a dictionary name mapping for the specified collection class with the specified entry class. 106 * 107 * @param typeName The dictionary name of the class. 108 * @param collectionClass The collection implementation class. 109 * @param entryClass The entry class. 110 * @return This object. 111 */ 112 protected BeanDictionaryMap append(String typeName, Class<? extends Collection> collectionClass, Object entryClass) { 113 assertValidParameter(entryClass); 114 put(typeName, a(collectionClass, entryClass)); 115 return this; 116 } 117 118 /** 119 * Add a dictionary name mapping for the specified map class with the specified key and value classes. 120 * 121 * @param typeName The dictionary name of the class. 122 * @param mapClass The map implementation class. 123 * @param keyClass The key class. 124 * @param valueClass The value class. 125 * @return This object. 126 */ 127 protected BeanDictionaryMap append(String typeName, Class<? extends Map> mapClass, Object keyClass, Object valueClass) { 128 assertValidParameter(keyClass); 129 assertValidParameter(valueClass); 130 put(typeName, a(mapClass, keyClass, valueClass)); 131 return this; 132 } 133}