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