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.transform;
014
015import java.util.*;
016
017import static org.apache.juneau.internal.ClassUtils.*;
018
019import org.apache.juneau.*;
020import org.apache.juneau.annotation.*;
021
022/**
023 * Parent class for all bean filters.
024 *
025 * <p>
026 * Bean filters are used to control aspects of how beans are handled during serialization and parsing.
027 *
028 * <p>
029 * Bean filters are created by {@link BeanFilterBuilder} which is the programmatic equivalent to the {@link Bean @Bean}
030 * annotation.
031 *
032 * <ul class='seealso'>
033 *    <li class='link'>{@doc BeanFilters}
034 * </ul>
035 */
036public final class BeanFilter {
037
038   private final Class<?> beanClass;
039   private final Set<String> bpi, bpx, bpro, bpwo;
040   private final PropertyNamer propertyNamer;
041   private final Class<?> interfaceClass, stopClass;
042   private final boolean sortProperties, fluentSetters;
043   private final String typeName;
044   private final Class<?>[] beanDictionary;
045   @SuppressWarnings("rawtypes")
046   private final BeanInterceptor interceptor;
047
048   /**
049    * Constructor.
050    */
051   BeanFilter(BeanFilterBuilder<?> builder) {
052      this.beanClass = builder.beanClass;
053      this.typeName = builder.typeName;
054      this.bpi = new LinkedHashSet<>(builder.bpi);
055      this.bpx = new LinkedHashSet<>(builder.bpx);
056      this.bpro = new LinkedHashSet<>(builder.bpro);
057      this.bpwo = new LinkedHashSet<>(builder.bpwo);
058      this.interfaceClass = builder.interfaceClass;
059      this.stopClass = builder.stopClass;
060      this.sortProperties = builder.sortProperties;
061      this.fluentSetters = builder.fluentSetters;
062      this.propertyNamer = castOrCreate(PropertyNamer.class, builder.propertyNamer);
063      this.beanDictionary =
064         builder.dictionary == null
065         ? null
066         : builder.dictionary.toArray(new Class<?>[builder.dictionary.size()]);
067      this.interceptor =
068         builder.interceptor == null
069         ? BeanInterceptor.DEFAULT
070         : castOrCreate(BeanInterceptor.class, builder.interceptor);
071   }
072
073   /**
074    * Static creator.
075    *
076    * @param <T> The class being filtered.
077    * @param c The class being filtered.
078    * @return A new instance of BeanFilterBuilder.
079    */
080   public static <T> BeanFilterBuilder<T> create(Class<T> c) {
081      return new BeanFilterBuilder<>(c);
082   }
083
084   /**
085    * Returns the bean class that this filter applies to.
086    *
087    * @return The bean class that this filter applies to.
088    */
089   public Class<?> getBeanClass() {
090      return beanClass;
091   }
092
093   /**
094    * Returns the dictionary name associated with this bean.
095    *
096    * @return The dictionary name associated with this bean, or <jk>null</jk> if no name is defined.
097    */
098   public String getTypeName() {
099      return typeName;
100   }
101
102   /**
103    * Returns the bean dictionary defined on this bean.
104    *
105    * @return The bean dictionary defined on this bean, or <jk>null</jk> if no bean dictionary is defined.
106    */
107   public Class<?>[] getBeanDictionary() {
108      return beanDictionary;
109   }
110
111   /**
112    * Returns the set and order of names of properties associated with a bean class.
113    *
114    * @return
115    *    The names of the properties associated with a bean class, or and empty set if all bean properties should
116    *    be used.
117    */
118   public Set<String> getBpi() {
119      return bpi;
120   }
121
122   /**
123    * Returns the list of properties to ignore on a bean.
124    *
125    * @return The names of the properties to ignore on a bean, or an empty set to not ignore any properties.
126    */
127   public Set<String> getBpx() {
128      return bpx;
129   }
130
131   /**
132    * Returns the list of read-only properties on a bean.
133    *
134    * @return The names of the read-only properties on a bean, or an empty set to not have any read-only properties.
135    */
136   public Set<String> getBpro() {
137      return bpro;
138   }
139
140   /**
141    * Returns the list of write-only properties on a bean.
142    *
143    * @return The names of the write-only properties on a bean, or an empty set to not have any write-only properties.
144    */
145   public Set<String> getBpwo() {
146      return bpwo;
147   }
148
149   /**
150    * Returns <jk>true</jk> if the properties defined on this bean class should be ordered alphabetically.
151    *
152    * <p>
153    * This method is only used when the {@link #getBpi()} method returns <jk>null</jk>.
154    * Otherwise, the ordering of the properties in the returned value is used.
155    *
156    * @return <jk>true</jk> if bean properties should be sorted.
157    */
158   public boolean isSortProperties() {
159      return sortProperties;
160   }
161
162   /**
163    * Returns <jk>true</jk> if we should find fluent setters.
164    *
165    * @return <jk>true</jk> if fluent setters should be found.
166    */
167   public boolean isFluentSetters() {
168      return fluentSetters;
169   }
170
171   /**
172    * Returns the {@link PropertyNamer} associated with the bean to tailor the names of bean properties.
173    *
174    * @return The property namer class, or <jk>null</jk> if no property namer is associated with this bean property.
175    */
176   public PropertyNamer getPropertyNamer() {
177      return propertyNamer;
178   }
179
180   /**
181    * Returns the interface class associated with this class.
182    *
183    * @return The interface class associated with this class, or <jk>null</jk> if no interface class is associated.
184    */
185   public Class<?> getInterfaceClass() {
186      return interfaceClass;
187   }
188
189   /**
190    * Returns the stop class associated with this class.
191    *
192    * @return The stop class associated with this class, or <jk>null</jk> if no stop class is associated.
193    */
194   public Class<?> getStopClass() {
195      return stopClass;
196   }
197
198   /**
199    * Calls the {@link BeanInterceptor#readProperty(Object, String, Object)} method on the registered property filters.
200    *
201    * @param bean The bean from which the property was read.
202    * @param name The property name.
203    * @param value The value just extracted from calling the bean getter.
204    * @return The value to serialize.  Default is just to return the existing value.
205    */
206   @SuppressWarnings("unchecked")
207   public Object readProperty(Object bean, String name, Object value) {
208      return interceptor.readProperty(bean, name, value);
209   }
210
211   /**
212    * Calls the {@link BeanInterceptor#writeProperty(Object, String, Object)} method on the registered property filters.
213    *
214    * @param bean The bean from which the property was read.
215    * @param name The property name.
216    * @param value The value just parsed.
217    * @return The value to serialize.  Default is just to return the existing value.
218    */
219   @SuppressWarnings("unchecked")
220   public Object writeProperty(Object bean, String name, Object value) {
221      return interceptor.writeProperty(bean, name, value);
222   }
223}