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.commons.bean;
018
019import java.util.*;
020
021import org.apache.juneau.commons.reflect.*;
022
023/**
024 * Bean-modeling SPI seam that exposes marshalling-aware {@link BeanMeta} construction hooks.
025 *
026 * <p>
027 * The bean-modeling layer in {@code commons.bean} can construct a {@link BeanMeta} from a {@link Class} plus a
028 * {@link BeanConfigContext} alone, but the full marshalling-side construction path also needs to:
029 * <ul>
030 *  <li>Read {@code @Marshalled} / {@code @BeanType} annotations to detect bean registration, dictionary names,
031 *      and the type-property name.
032 *  <li>Build a {@code BeanRegistry} for polymorphic dispatch (bean-level and per-property).
033 *  <li>Walk the parent class/interface hierarchy to find an inherited dictionary name.
034 * </ul>
035 *
036 * <p>
037 * These operations require the marshalling-side {@code MarshallingContext}, so they are exposed here as SPI
038 * methods that take the marshalling context as an opaque {@link Object}.  The marshalling-side implementation
039 * in {@code MarshalledBeanMetaInitializer} narrows the argument internally; the bean-modeling layer never
040 * imports the marshalling-side types.
041 *
042 * <p>
043 * The default {@link #NOOP} implementation is wired on the commons-side path and returns conservative defaults
044 * (no marshalling-side help available).  {@code @BeanType} reads remain functional via the configured
045 * {@link BeanConfigContext#getAnnotationProvider()}.
046 *
047 * <h5 class='topic'>Thread safety</h5>
048 * Thread safety depends on implementation.
049 *
050 * @see BeanConfigContext.Builder#beanMetaInitializer(BeanMetaInitializer)
051 */
052public interface BeanMetaInitializer {
053
054   /**
055    * Singleton commons-side default — no marshalling-side knowledge.
056    *
057    * <p>
058    * Returns conservative defaults: no bean dictionary, no inherited type-names, no {@code @Marshalled} reads.
059    * {@link #hasBeanRegistrationAnnotation(BeanConfigContext, ClassInfo)} still reads {@code @BeanType} via
060    * the supplied {@link BeanConfigContext#getAnnotationProvider() annotation provider}.
061    */
062   BeanMetaInitializer NOOP = new BeanMetaInitializer() {
063      @Override
064      public boolean hasBeanRegistrationAnnotation(BeanConfigContext config, ClassInfo classInfo) {
065         return ! config.getAnnotationProvider().find(BeanType.class, classInfo).isEmpty();
066      }
067
068      @Override
069      public String resolveTypePropertyName(BeanConfigContext config, ClassInfo classInfo) {
070         return null;
071      }
072
073      @Override
074      public String findMarshalledTypeName(BeanConfigContext config, ClassInfo classInfo) {
075         return null;
076      }
077
078      @Override
079      public BeanRegistryLookup buildBeanRegistry(Object marshallingContext, BeanFilter beanFilter, ClassInfo classInfo, BeanConfigContext config) {
080         return null;
081      }
082
083      @Override
084      public BeanRegistryLookup buildPropertyBeanRegistry(Object marshallingContext, BeanRegistryLookup parent, List<ClassInfo> dictionaryClasses) {
085         return null;
086      }
087
088      @Override
089      public String findTypeNameInParents(Object marshallingContext, ClassInfo classInfo, Class<?> rawClass) {
090         return null;
091      }
092
093      @Override
094      public BeanFilter buildBeanFilter(BeanInfo<?> cm) {
095         return null;
096      }
097   };
098
099   /**
100    * Returns <jk>true</jk> if the supplied class has a "registered as bean" annotation (e.g. {@code @Marshalled}
101    * or {@code @BeanType}).  Used to relax constructor-visibility / serializable / class-visibility checks during
102    * bean detection.
103    *
104    * @param config The bean-modeling configuration.
105    * @param classInfo The bean's class info.
106    * @return <jk>true</jk> if the class has a registration annotation.
107    */
108   boolean hasBeanRegistrationAnnotation(BeanConfigContext config, ClassInfo classInfo);
109
110   /**
111    * Returns the marshalling-side {@code @Marshalled(typePropertyName)} value for the bean, or <jk>null</jk> if
112    * not set.  Callers fall back to {@link BeanConfigContext#getBeanTypePropertyName()} when this returns <jk>null</jk>.
113    *
114    * @param config The bean-modeling configuration.
115    * @param classInfo The bean's class info.
116    * @return The resolved type property name, or <jk>null</jk>.
117    */
118   String resolveTypePropertyName(BeanConfigContext config, ClassInfo classInfo);
119
120   /**
121    * Returns the marshalling-side {@code @Marshalled(typeName)} value for the bean, or <jk>null</jk> if not set.
122    *
123    * @param config The bean-modeling configuration.
124    * @param classInfo The bean's class info.
125    * @return The marshalled type name, or <jk>null</jk>.
126    */
127   String findMarshalledTypeName(BeanConfigContext config, ClassInfo classInfo);
128
129   /**
130    * Builds the bean-level {@link BeanRegistryLookup} for the supplied class.  Returns <jk>null</jk> on the
131    * commons-side path (no marshalling context).
132    *
133    * @param marshallingContext The marshalling-side context (as an opaque {@link Object}).  Can be <jk>null</jk>.  The effect is implementation-dependent — see {@code org.apache.juneau.marshall.MarshalledBeanMetaInitializer}, the sole concrete implementer of this SPI.
134    * @param beanFilter The bean filter applied to this bean meta.  Can be <jk>null</jk>.  The effect is implementation-dependent — see {@code org.apache.juneau.marshall.MarshalledBeanMetaInitializer}.
135    * @param classInfo The class info of the bean.  Must not be <jk>null</jk>.
136    * @param config The bean-modeling configuration.  Must not be <jk>null</jk>.
137    * @return The bean-level registry, or <jk>null</jk>.
138    */
139   BeanRegistryLookup buildBeanRegistry(Object marshallingContext, BeanFilter beanFilter, ClassInfo classInfo, BeanConfigContext config);
140
141   /**
142    * Builds the per-property {@link BeanRegistryLookup} chained on top of the bean-level registry.
143    *
144    * @param marshallingContext The marshalling-side context.  Must not be <jk>null</jk> on the marshalling path.
145    * @param parent The bean-level registry (chained behind the per-property one).  May be <jk>null</jk>.
146    * @param dictionaryClasses The per-property dictionary class infos.  Must not be <jk>null</jk>.
147    * @return The per-property registry, or <jk>null</jk> when there is no marshalling context.
148    */
149   BeanRegistryLookup buildPropertyBeanRegistry(Object marshallingContext, BeanRegistryLookup parent, List<ClassInfo> dictionaryClasses);
150
151   /**
152    * Walks the parent classes/interfaces of {@code classInfo} and returns the first dictionary-name mapping for
153    * {@code rawClass} found in any parent's registry, or <jk>null</jk> if none.
154    *
155    * @param marshallingContext The marshalling-side context.  Can be <jk>null</jk>.  The effect is implementation-dependent — see {@code org.apache.juneau.marshall.MarshalledBeanMetaInitializer}.
156    * @param classInfo The bean's class info.
157    * @param rawClass The raw class to look up.
158    * @return The dictionary name found in a parent's registry, or <jk>null</jk>.
159    */
160   String findTypeNameInParents(Object marshallingContext, ClassInfo classInfo, Class<?> rawClass);
161
162   /**
163    * Builds the marshalling-side {@link BeanFilter} for the supplied class, reading {@code @Marshalled} and
164    * {@code @BeanType} annotations.  Returns <jk>null</jk> on the commons-side path (no marshalling-side
165    * filter construction is available).
166    *
167    * @param cm The bean type info.
168    * @return The bean filter, or <jk>null</jk>.
169    */
170   BeanFilter buildBeanFilter(BeanInfo<?> cm);
171}