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