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 static org.apache.juneau.internal.StringUtils.*;
016
017import org.apache.juneau.*;
018import org.apache.juneau.annotation.*;
019import org.apache.juneau.internal.*;
020
021/**
022 * Parent class for all bean filters.
023 *
024 * <p>
025 * Bean filters are used to control aspects of how beans are handled during serialization and parsing.
026 *
027 * <p>
028 * Bean filters are created by {@link BeanFilterBuilder} which is the programmatic equivalent to the {@link Bean @Bean}
029 * annotation.
030 *
031 * <h5 class='section'>See Also:</h5>
032 * <ul>
033 *    <li class='link'>{@doc juneau-marshall.Transforms.BeanFilters}
034 * </ul>
035 */
036public final class BeanFilter {
037
038   private final Class<?> beanClass;
039   private final String[] properties, excludeProperties;
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   private final PropertyFilter propertyFilter;
046
047   /**
048    * Constructor.
049    */
050   BeanFilter(BeanFilterBuilder<?> builder) {
051      this.beanClass = builder.beanClass;
052      this.typeName = builder.typeName;
053      this.properties = split(builder.includeProperties, ',');
054      this.excludeProperties = split(builder.excludeProperties, ',');
055      this.interfaceClass = builder.interfaceClass;
056      this.stopClass = builder.stopClass;
057      this.sortProperties = builder.sortProperties;
058      this.fluentSetters = builder.fluentSetters;
059      this.propertyNamer = ClassUtils.newInstance(PropertyNamer.class, builder.propertyNamer);
060      this.beanDictionary =
061         builder.beanDictionary == null
062         ? null
063         : builder.beanDictionary.toArray(new Class<?>[builder.beanDictionary.size()]);
064      this.propertyFilter =
065         builder.propertyFilter == null
066         ? PropertyFilter.DEFAULT
067         : ClassUtils.newInstance(PropertyFilter.class, builder.propertyFilter);
068   }
069
070   /**
071    * Returns the bean class that this filter applies to.
072    *
073    * @return The bean class that this filter applies to.
074    */
075   public Class<?> getBeanClass() {
076      return beanClass;
077   }
078
079   /**
080    * Returns the dictionary name associated with this bean.
081    *
082    * @return The dictionary name associated with this bean, or <jk>null</jk> if no name is defined.
083    */
084   public String getTypeName() {
085      return typeName;
086   }
087
088   /**
089    * Returns the set and order of names of properties associated with a bean class.
090    *
091    * @return
092    *    The name of the properties associated with a bean class, or <jk>null</jk> if all bean properties should
093    *    be used.
094    */
095   public String[] getProperties() {
096      return properties;
097   }
098
099   /**
100    * Returns the bean dictionary defined on this bean.
101    *
102    * @return The bean dictionary defined on this bean, or <jk>null</jk> if no bean dictionary is defined.
103    */
104   public Class<?>[] getBeanDictionary() {
105      return beanDictionary;
106   }
107
108   /**
109    * Returns <jk>true</jk> if the properties defined on this bean class should be ordered alphabetically.
110    *
111    * <p>
112    * This method is only used when the {@link #getProperties()} method returns <jk>null</jk>.
113    * Otherwise, the ordering of the properties in the returned value is used.
114    *
115    * @return <jk>true</jk> if bean properties should be sorted.
116    */
117   public boolean isSortProperties() {
118      return sortProperties;
119   }
120
121   /**
122    * Returns <jk>true</jk> if we should find fluent setters.
123    *
124    * @return <jk>true</jk> if fluent setters should be found.
125    */
126   public boolean isFluentSetters() {
127      return fluentSetters;
128   }
129
130   /**
131    * Returns the list of properties to ignore on a bean.
132    *
133    * @return The name of the properties to ignore on a bean, or <jk>null</jk> to not ignore any properties.
134    */
135   public String[] getExcludeProperties() {
136      return excludeProperties;
137   }
138
139   /**
140    * Returns the {@link PropertyNamer} associated with the bean to tailor the names of bean properties.
141    *
142    * @return The property namer class, or <jk>null</jk> if no property namer is associated with this bean property.
143    */
144   public PropertyNamer getPropertyNamer() {
145      return propertyNamer;
146   }
147
148   /**
149    * Returns the interface class associated with this class.
150    *
151    * @return The interface class associated with this class, or <jk>null</jk> if no interface class is associated.
152    */
153   public Class<?> getInterfaceClass() {
154      return interfaceClass;
155   }
156
157   /**
158    * Returns the stop class associated with this class.
159    *
160    * @return The stop class associated with this class, or <jk>null</jk> if no stop class is associated.
161    */
162   public Class<?> getStopClass() {
163      return stopClass;
164   }
165
166   /**
167    * Calls the {@link PropertyFilter#readProperty(Object, String, Object)} method on the registered property filters.
168    *
169    * @param bean The bean from which the property was read.
170    * @param name The property name.
171    * @param value The value just extracted from calling the bean getter.
172    * @return The value to serialize.  Default is just to return the existing value.
173    */
174   public Object readProperty(Object bean, String name, Object value) {
175      return propertyFilter.readProperty(bean, name, value);
176   }
177
178   /**
179    * Calls the {@link PropertyFilter#writeProperty(Object, String, Object)} method on the registered property filters.
180    *
181    * @param bean The bean from which the property was read.
182    * @param name The property name.
183    * @param value The value just parsed.
184    * @return The value to serialize.  Default is just to return the existing value.
185    */
186   public Object writeProperty(Object bean, String name, Object value) {
187      return propertyFilter.writeProperty(bean, name, value);
188   }
189}