All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.juneau.BeanRegistry Maven / Gradle / Ivy

There is a newer version: 9.0.1
Show newest version
// ***************************************************************************************************************************
// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
// * to you under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0                                                                             *
// *                                                                                                                         *
// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
// * specific language governing permissions and limitations under the License.                                              *
// ***************************************************************************************************************************
package org.apache.juneau;

import static org.apache.juneau.internal.ClassUtils.*;
import static org.apache.juneau.internal.StringUtils.*;

import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.*;

import org.apache.juneau.annotation.*;

/**
 * A lookup table for resolving bean types by name.
 *
 * 

* In a nutshell, provides a simple mapping of bean class objects to identifying names. * *

* Class names are defined through the {@link Bean#typeName() @Bean(typeName)} annotation. * *

* The dictionary is used by the framework in the following ways: *

    *
  • If a class type cannot be inferred through reflection during parsing, then a helper "_type" is added * to the serialized output using the name defined for that class in this dictionary. This helps determine the * real class at parse time. *
  • The dictionary name is used as element names when serialized to XML. *
*/ public class BeanRegistry { private final Map> map; private final Map,String> reverseMap; private final BeanContext beanContext; private final boolean isEmpty; BeanRegistry(BeanContext beanContext, BeanRegistry parent, Class...classes) { this.beanContext = beanContext; this.map = new ConcurrentHashMap<>(); this.reverseMap = new ConcurrentHashMap<>(); for (Class c : beanContext.getBeanDictionaryClasses()) addClass(c); if (parent != null) for (Map.Entry> e : parent.map.entrySet()) addToMap(e.getKey(), e.getValue()); for (Class c : classes) addClass(c); isEmpty = map.isEmpty(); } private void addClass(Class c) { try { if (c != null) { if (isParentClass(Collection.class, c)) { @SuppressWarnings("rawtypes") Collection cc = beanContext.newInstance(Collection.class, c); for (Object o : cc) { if (o instanceof Class) addClass((Class)o); else throw new BeanRuntimeException("Collection class ''{0}'' passed to BeanRegistry does not contain Class objects.", c.getName()); } } else if (isParentClass(Map.class, c)) { Map m = beanContext.newInstance(Map.class, c); for (Map.Entry e : m.entrySet()) { String typeName = asString(e.getKey()); Object v = e.getValue(); ClassMeta val = null; if (v instanceof Type) val = beanContext.getClassMeta((Type)v); else if (v.getClass().isArray()) val = getTypedClassMeta(v); else throw new BeanRuntimeException("Class ''{0}'' was passed to BeanRegistry but value of type ''{1}'' found in map is not a Type object.", c.getName(), v.getClass().getName()); addToMap(typeName, val); } } else { Bean b = c.getAnnotation(Bean.class); if (b == null || b.typeName().isEmpty()) throw new BeanRuntimeException("Class ''{0}'' was passed to BeanRegistry but it doesn't have a @Bean(typeName) annotation defined.", c.getName()); addToMap(b.typeName(), beanContext.getClassMeta(c)); } } } catch (BeanRuntimeException e) { throw e; } catch (Exception e) { throw new BeanRuntimeException(e); } } private ClassMeta getTypedClassMeta(Object array) { int len = Array.getLength(array); if (len == 0) throw new BeanRuntimeException("Map entry had an empty array value."); Type type = (Type)Array.get(array, 0); Type[] args = new Type[len-1]; for (int i = 1; i < len; i++) args[i-1] = (Type)Array.get(array, i); return beanContext.getClassMeta(type, args); } private void addToMap(String typeName, ClassMeta cm) { map.put(typeName, cm); reverseMap.put(cm.innerClass, typeName); } /** * Gets the class metadata for the specified bean type name. * * @param typeName * The bean type name as defined by {@link Bean#typeName() @Bean(typeName)}. * Can include multi-dimensional array type names (e.g. "X^^"). * @return The class metadata for the bean. */ public ClassMeta getClassMeta(String typeName) { if (isEmpty) return null; if (typeName == null) return null; ClassMeta cm = map.get(typeName); if (cm != null) return cm; if (typeName.charAt(typeName.length()-1) == '^') { cm = getClassMeta(typeName.substring(0, typeName.length()-1)); if (cm != null) { cm = beanContext.getClassMeta(Array.newInstance(cm.innerClass, 1).getClass()); map.put(typeName, cm); } return cm; } return null; } /** * Given the specified class, return the dictionary name for it. * * @param c The class to lookup in this registry. * @return The dictionary name for the specified class in this registry, or null if not found. */ public String getTypeName(ClassMeta c) { if (isEmpty) return null; return reverseMap.get(c.innerClass); } /** * Returns true if this dictionary has an entry for the specified type name. * * @param typeName The bean type name. * @return true if this dictionary has an entry for the specified type name. */ public boolean hasName(String typeName) { return getClassMeta(typeName) != null; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append('{'); for (Map.Entry> e : map.entrySet()) sb.append(e.getKey()).append(":").append(e.getValue().toString(true)).append(", "); sb.append('}'); return sb.toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy