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