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.swap;
018
019/**
020 * Bean interceptor.
021 *
022 * <p>
023 * Bean interceptors intercept calls to bean getters and setters to allow them to override values in transit.
024 *
025 * <h5 class='section'>Example:</h5>
026 * <p class='bjava'>
027 *    <jc>// Interceptor that strips out sensitive information on Address beans.</jc>
028 *    <jk>public class</jk> AddressInterceptor <jk>extends</jk> BeanInterceptor&lt;Address&gt; {
029 *
030 *       <ja>@Override</ja>
031 *       <jk>public</jk> Object readProperty(Address <jv>bean</jv>, String <jv>name</jv>, Object <jv>value</jv>) {
032 *          <jk>if</jk> (<js>"taxInfo"</js>.equals(<jv>name</jv>))
033 *             <jk>return</jk> <js>"redacted"</js>;
034 *          <jk>return</jk> <jv>value</jv>;
035 *       }
036 *
037 *       <ja>@Override</ja>
038 *       <jk>public</jk> Object writeProperty(Address <jv>bean</jv>, String <jv>name</jv>, Object <jv>value</jv>) {
039 *          <jk>if</jk> (<js>"taxInfo"</js>.equals(<jv>name</jv>) &amp;&amp; <js>"redacted"</js>.equals(<jv>value</jv>))
040 *             <jk>return</jk> TaxInfoUtils.<jsm>lookup</jsm>(<jv>bean</jv>.getStreet(), <jv>bean</jv>.getCity(), <jv>bean</jv>.getState());
041 *          <jk>return</jk> <jv>value</jv>;
042 *       }
043 *    }
044 * </p>
045 *
046 * <p>
047 * Bean interceptors are registered in the following way:
048 * <ul class='javatree'>
049 *    <li class='ja'>{@link org.apache.juneau.annotation.Bean#interceptor() @Bean(interceptor)}
050 *    <li class='jm'>{@link org.apache.juneau.BeanContext.Builder#beanInterceptor(Class,Class)}
051 * </ul>
052 *
053 * <h5 class='section'>Example:</h5>
054 * <p class='bjava'>
055 *    <jc>// Register interceptor on bean class.</jc>
056 *    <ja>@Bean</ja>(interceptor=AddressInterceptor.<jk>class</jk>)
057 *    <jk>public class</jk> Address {
058 *       <jk>public</jk> String getTaxInfo() {...}
059 *       <jk>public void</jk> setTaxInfo(String <jv>value</jv>) {...}
060 *    }
061 * </p>
062 *
063 * <h5 class='section'>See Also:</h5><ul>
064 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/SwapBasics">Swap Basics</a>
065 * </ul>
066 *
067 * @param <T> The bean type.
068 */
069public class BeanInterceptor<T> {
070
071   /** Non-existent bean interceptor. */
072   public static final class Void extends BeanInterceptor<Object> {}
073
074   /**
075    * Default reusable property filter instance.
076    */
077   public static final BeanInterceptor<Object> DEFAULT = new BeanInterceptor<>();
078
079   /**
080    * Property read interceptor.
081    *
082    * <p>
083    * Subclasses can override this property to convert property values to some other object just before serialization.
084    *
085    * <h5 class='section'>Example:</h5>
086    * <p class='bjava'>
087    *    <jc>// Address filter that strips out sensitive information.</jc>
088    *    <jk>public class</jk> AddressInterceptor <jk>extends</jk> BeanInterceptor&lt;Address&gt; {
089    *
090    *       <jk>public</jk> Object readProperty(Address <jv>bean</jv>, String <jv>name</jv>, Object <jv>value</jv>) {
091    *          <jk>if</jk> (<js>"taxInfo"</js>.equals(<jv>name</jv>))
092    *             <jk>return</jk> <js>"redacted"</js>;
093    *          <jk>return</jk> <jv>value</jv>;
094    *       }
095    *    }
096    * </p>
097    *
098    * @param bean The bean from which the property was read.
099    * @param name The property name.
100    * @param value The value just extracted from calling the bean getter.
101    * @return The value to serialize.  Default is just to return the existing value.
102    */
103   public Object readProperty(T bean, String name, Object value) {
104      return value;
105   }
106
107   /**
108    * Property write interceptor.
109    *
110    * <p>
111    * Subclasses can override this property to convert property values to some other object just before calling the
112    * bean setter.
113    *
114    * <h5 class='section'>Example:</h5>
115    * <p class='bjava'>
116    *    <jc>// Address filter that strips out sensitive information.</jc>
117    *    <jk>public class</jk> AddressInterceptor <jk>extends</jk> BeanInterceptor&lt;Address&gt; {
118    *
119    *       <jk>public</jk> Object writeProperty(Address <jv>bean</jv>, String <jv>name</jv>, Object <jv>value</jv>) {
120    *          <jk>if</jk> (<js>"taxInfo"</js>.equals(<jv>name</jv>) &amp;&amp; <js>"redacted"</js>.equals(<jv>value</jv>))
121    *             <jk>return</jk> TaxInfoUtils.<jsm>lookup</jsm>(<jv>bean</jv>.getStreet(), <jv>bean</jv>.getCity(), <jv>bean</jv>.getState());
122    *          <jk>return</jk> <jv>value</jv>;
123    *       }
124    *    }
125    * </p>
126    *
127    * @param bean The bean from which the property was read.
128    * @param name The property name.
129    * @param value The value just parsed.
130    * @return The value to serialize.  Default is just to return the existing value.
131    */
132   public Object writeProperty(T bean, String name, Object value) {
133      return value;
134   }
135}