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; 014 015import java.lang.reflect.*; 016import java.util.*; 017 018import org.apache.juneau.json.*; 019import org.apache.juneau.reflect.*; 020 021/** 022 * Provides an {@link InvocationHandler} for creating beans from bean interfaces. 023 * 024 * <p> 025 * If the {@code useInterfaceProxies} setting is enabled in {@link BeanContext}, this is the class that creates 026 * instances of beans from interfaces. 027 * 028 * <h5 class='section'>See Also:</h5><ul> 029 030 * </ul> 031 * 032 * @param <T> The interface class 033 */ 034public class BeanProxyInvocationHandler<T> implements InvocationHandler { 035 036 private final BeanMeta<T> meta; // The BeanMeta for this instance 037 private Map<String, Object> beanProps; // The map of property names to bean property values. 038 039 /** 040 * Constructs with the specified {@link BeanMeta}. 041 * 042 * @param meta The bean meta data. 043 */ 044 public BeanProxyInvocationHandler(BeanMeta<T> meta) { 045 this.meta = meta; 046 this.beanProps = new HashMap<>(); 047 } 048 049 /** 050 * Implemented to handle the method called. 051 */ 052 @Override /* InvocationHandler */ 053 public Object invoke(Object proxy, Method method, Object[] args) { 054 MethodInfo mi = MethodInfo.of(method); 055 if (mi.hasName("equals") && mi.hasParamTypes(java.lang.Object.class)) { 056 Object arg = args[0]; 057 if (arg == null) 058 return false; 059 if (proxy == arg) 060 return true; 061 if (proxy.getClass() == arg.getClass()) { 062 InvocationHandler ih = Proxy.getInvocationHandler(arg); 063 if (ih instanceof BeanProxyInvocationHandler) { 064 return this.beanProps.equals(((BeanProxyInvocationHandler<?>)ih).beanProps); 065 } 066 } 067 BeanMap<Object> bean = this.meta.ctx.toBeanMap(arg); 068 return this.beanProps.equals(bean); 069 } 070 071 if (mi.hasName("hashCode") && mi.hasNoParams()) 072 return Integer.valueOf(this.beanProps.hashCode()); 073 074 if (mi.hasName("toString") && mi.hasNoParams()) 075 return Json5Serializer.DEFAULT.toString(this.beanProps); 076 077 String prop = this.meta.getterProps.get(method); 078 if (prop != null) 079 return this.beanProps.get(prop); 080 081 prop = this.meta.setterProps.get(method); 082 if (prop != null) { 083 this.beanProps.put(prop, args[0]); 084 return null; 085 } 086 087 throw new UnsupportedOperationException("Unsupported bean method. method='"+method+"'"); 088 } 089}