From c7ca1c3168ba0b626e66a60f4b8f80b0949f4307 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miko=C5=82aj=20Koziarkiewicz?= <>
Date: Sun, 24 Jun 2012 19:40:58 +0200
Subject: [PATCH 01/82] Added android adaptations.
---
NOTICE | 52 +
.../java/custom/beans/BeanDescriptor.java | 105 ++
src/main/java/custom/beans/BeanInfo.java | 36 +
.../java/custom/beans/EventSetDescriptor.java | 432 +++++
.../java/custom/beans/ExceptionListener.java | 23 +
src/main/java/custom/beans/Expression.java | 72 +
.../java/custom/beans/FeatureDescriptor.java | 249 +++
.../beans/IndexedPropertyDescriptor.java | 383 +++++
.../custom/beans/IntrospectionException.java | 27 +
src/main/java/custom/beans/Introspector.java | 368 ++++
.../java/custom/beans/MethodDescriptor.java | 109 ++
.../custom/beans/ParameterDescriptor.java | 25 +
.../custom/beans/PropertyChangeEvent.java | 62 +
.../custom/beans/PropertyChangeListener.java | 25 +
.../java/custom/beans/PropertyDescriptor.java | 300 ++++
.../java/custom/beans/PropertyEditor.java | 43 +
.../custom/beans/PropertyVetoException.java | 55 +
.../java/custom/beans/SimpleBeanInfo.java | 54 +
.../java/custom/beans/StandardBeanInfo.java | 1505 +++++++++++++++++
src/main/java/custom/beans/Statement.java | 610 +++++++
src/main/java/custom/beans/XMLDecoder.java | 705 ++++++++
.../org/apache/harmony/beans/Argument.java | 62 +
.../org/apache/harmony/beans/BeansUtils.java | 122 ++
.../org/apache/harmony/beans/Command.java | 865 ++++++++++
.../org/apache/harmony/beans/Handler.java | 146 ++
.../harmony/beans/internal/nls/Messages.java | 240 +++
.../beans/internal/nls/messages.properties | 133 ++
.../template/builder/BeansFieldEntry.java | 2 +-
.../ReflectionBeansTemplateBuilder.java | 8 +-
29 files changed, 6813 insertions(+), 5 deletions(-)
create mode 100644 NOTICE
create mode 100644 src/main/java/custom/beans/BeanDescriptor.java
create mode 100644 src/main/java/custom/beans/BeanInfo.java
create mode 100644 src/main/java/custom/beans/EventSetDescriptor.java
create mode 100644 src/main/java/custom/beans/ExceptionListener.java
create mode 100644 src/main/java/custom/beans/Expression.java
create mode 100644 src/main/java/custom/beans/FeatureDescriptor.java
create mode 100644 src/main/java/custom/beans/IndexedPropertyDescriptor.java
create mode 100644 src/main/java/custom/beans/IntrospectionException.java
create mode 100644 src/main/java/custom/beans/Introspector.java
create mode 100644 src/main/java/custom/beans/MethodDescriptor.java
create mode 100644 src/main/java/custom/beans/ParameterDescriptor.java
create mode 100644 src/main/java/custom/beans/PropertyChangeEvent.java
create mode 100644 src/main/java/custom/beans/PropertyChangeListener.java
create mode 100644 src/main/java/custom/beans/PropertyDescriptor.java
create mode 100644 src/main/java/custom/beans/PropertyEditor.java
create mode 100644 src/main/java/custom/beans/PropertyVetoException.java
create mode 100644 src/main/java/custom/beans/SimpleBeanInfo.java
create mode 100644 src/main/java/custom/beans/StandardBeanInfo.java
create mode 100644 src/main/java/custom/beans/Statement.java
create mode 100644 src/main/java/custom/beans/XMLDecoder.java
create mode 100644 src/main/java/org/apache/harmony/beans/Argument.java
create mode 100644 src/main/java/org/apache/harmony/beans/BeansUtils.java
create mode 100644 src/main/java/org/apache/harmony/beans/Command.java
create mode 100644 src/main/java/org/apache/harmony/beans/Handler.java
create mode 100644 src/main/java/org/apache/harmony/beans/internal/nls/Messages.java
create mode 100644 src/main/java/org/apache/harmony/beans/internal/nls/messages.properties
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 000000000..ab41a4cb6
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,52 @@
+This project uses code from the ASF Apache Harmony project. The following are the relevant notices
+from that project, included in order to comply with its license requirements.
+-------------------
+Apache Harmony
+Copyright 2006, 2010 The Apache Software Foundation.
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+Portions of Apache Harmony were originally developed by
+Intel Corporation and are licensed to the Apache Software
+Foundation under the "Software Grant and Corporate Contribution
+License Agreement" and for which the following copyright notices
+apply
+ (C) Copyright 2005 Intel Corporation
+ (C) Copyright 2005-2006 Intel Corporation
+ (C) Copyright 2006 Intel Corporation
+
+Portions of Apache Harmony's Class Library TEXT module contain JavaDoc
+derived from the ICU project.
+Copyright (c) 1995-2008 International Business Machines Corporation and others
+
+
+The Apache Harmony Development Kit (HDK) contains a jar file from the
+Apache Derby Project for which the following notice applies:
+
+Apache Derby
+Copyright 2004-2007 The Apache Software Foundation
+
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).
+
+Portions of Derby were originally developed by
+International Business Machines Corporation and are
+licensed to the Apache Software Foundation under the
+"Software Grant and Corporate Contribution License Agreement",
+informally known as the "Derby CLA".
+The following copyright notice(s) were affixed to portions of the code
+with which this file is now or was at one time distributed
+and are placed here unaltered.
+
+(C) Copyright 1997,2004 International Business Machines Corporation.
+All rights reserved.
+
+(C) Copyright IBM Corp. 2003.
+
+The portion of the functionTests under 'nist' was originally
+developed by the National Institute of Standards and Technology (NIST),
+an agency of the United States Department of Commerce, and adapted by
+International Business Machines Corporation in accordance with the NIST
+Software Acknowledgment and Redistribution document at
+http://www.itl.nist.gov/div897/ctg/sql_form.htm
\ No newline at end of file
diff --git a/src/main/java/custom/beans/BeanDescriptor.java b/src/main/java/custom/beans/BeanDescriptor.java
new file mode 100644
index 000000000..f0b963833
--- /dev/null
+++ b/src/main/java/custom/beans/BeanDescriptor.java
@@ -0,0 +1,105 @@
+/* MODIFIED FOR THE MSGPACK PROJECT
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package custom.beans;
+
+
+/**
+ * Describes a bean's global information.
+ */
+public class BeanDescriptor extends FeatureDescriptor {
+
+ private Class> beanClass;
+
+ private Class> customizerClass;
+
+ /**
+ *
+ * Constructs an instance with the bean's {@link Class} and a customizer
+ * {@link Class}. The descriptor's {@link #getName()} is set as the
+ * unqualified name of the beanClass.
+ *
+ * Constructs an instance with the bean's {@link Class}. The descriptor's
+ * {@link #getName()} is set as the unqualified name of the
+ * beanClass.
+ *
+ * Utility method for getting the unqualified name of a {@link Class}.
+ *
+ *
+ * @param leguminaClass
+ * The Class to get the name from.
+ * @return A String instance or null.
+ */
+ private String getShortClassName(Class> leguminaClass) {
+ if(leguminaClass == null) {
+ return null;
+ }
+ String beanClassName = leguminaClass.getName();
+ int lastIndex = beanClassName.lastIndexOf("."); //$NON-NLS-1$
+ return (lastIndex == -1) ? beanClassName : beanClassName.substring(lastIndex + 1);
+ }
+
+}
diff --git a/src/main/java/custom/beans/BeanInfo.java b/src/main/java/custom/beans/BeanInfo.java
new file mode 100644
index 000000000..2c4a24ab4
--- /dev/null
+++ b/src/main/java/custom/beans/BeanInfo.java
@@ -0,0 +1,36 @@
+/* MODIFIED FOR THE MSGPACK PROJECT
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package custom.beans;
+
+
+public interface BeanInfo {
+
+ public PropertyDescriptor[] getPropertyDescriptors();
+
+ public MethodDescriptor[] getMethodDescriptors();
+
+ public EventSetDescriptor[] getEventSetDescriptors();
+
+ public BeanInfo[] getAdditionalBeanInfo();
+
+ public BeanDescriptor getBeanDescriptor();
+
+ public int getDefaultPropertyIndex();
+
+ public int getDefaultEventIndex();
+}
diff --git a/src/main/java/custom/beans/EventSetDescriptor.java b/src/main/java/custom/beans/EventSetDescriptor.java
new file mode 100644
index 000000000..db5063914
--- /dev/null
+++ b/src/main/java/custom/beans/EventSetDescriptor.java
@@ -0,0 +1,432 @@
+/* MODIFIED FOR THE MSGPACK PROJECT
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package custom.beans;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.TooManyListenersException;
+import org.apache.harmony.beans.internal.nls.Messages;
+
+public class EventSetDescriptor extends FeatureDescriptor {
+ private Class> listenerType;
+
+ private ArrayList listenerMethodDescriptors;
+
+ private Method[] listenerMethods;
+
+ private Method getListenerMethod;
+
+ private Method addListenerMethod;
+
+ private Method removeListenerMethod;
+
+ private boolean unicast;
+
+ private boolean inDefaultEventSet = true;
+
+ public EventSetDescriptor(Class> sourceClass, String eventSetName,
+ Class> listenerType, String listenerMethodName)
+ throws IntrospectionException {
+ checkNotNull(sourceClass, eventSetName, listenerType,
+ listenerMethodName);
+ setName(eventSetName);
+ this.listenerType = listenerType;
+
+ Method method = findListenerMethodByName(listenerMethodName);
+ checkEventType(eventSetName, method);
+ listenerMethodDescriptors = new ArrayList();
+ listenerMethodDescriptors.add(new MethodDescriptor(method));
+ addListenerMethod = findMethodByPrefix(sourceClass, "add", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ removeListenerMethod = findMethodByPrefix(sourceClass, "remove", ""); //$NON-NLS-1$ //$NON-NLS-2$
+
+ if (addListenerMethod == null || removeListenerMethod == null) {
+ throw new IntrospectionException(Messages.getString("custom.beans.38")); //$NON-NLS-1$
+ }
+
+ getListenerMethod = findMethodByPrefix(sourceClass, "get", "s"); //$NON-NLS-1$ //$NON-NLS-2$
+ unicast = isUnicastByDefault(addListenerMethod);
+ }
+
+ public EventSetDescriptor(Class> sourceClass, String eventSetName,
+ Class> listenerType, String[] listenerMethodNames,
+ String addListenerMethodName, String removeListenerMethodName)
+ throws IntrospectionException {
+ this(sourceClass, eventSetName, listenerType, listenerMethodNames,
+ addListenerMethodName, removeListenerMethodName, null);
+
+ }
+
+ public EventSetDescriptor(Class> sourceClass, String eventSetName,
+ Class> listenerType, String[] listenerMethodNames,
+ String addListenerMethodName, String removeListenerMethodName,
+ String getListenerMethodName) throws IntrospectionException {
+
+ checkNotNull(sourceClass, eventSetName, listenerType,
+ listenerMethodNames);
+
+ setName(eventSetName);
+ this.listenerType = listenerType;
+
+ listenerMethodDescriptors = new ArrayList();
+ for (String element : listenerMethodNames) {
+ Method m = findListenerMethodByName(element);
+
+ // checkEventType(eventSetName, m);
+ listenerMethodDescriptors.add(new MethodDescriptor(m));
+ }
+
+ if (addListenerMethodName != null) {
+ this.addListenerMethod = findAddRemoveListenerMethod(sourceClass,
+ addListenerMethodName);
+ }
+ if (removeListenerMethodName != null) {
+ this.removeListenerMethod = findAddRemoveListenerMethod(
+ sourceClass, removeListenerMethodName);
+ }
+ if (getListenerMethodName != null) {
+ this.getListenerMethod = findGetListenerMethod(sourceClass,
+ getListenerMethodName);
+ }
+ this.unicast = isUnicastByDefault(addListenerMethod);
+ }
+
+ private Method findListenerMethodByName(String listenerMethodName)
+ throws IntrospectionException {
+ Method result = null;
+ Method[] methods = listenerType.getMethods();
+ for (Method method : methods) {
+ if (listenerMethodName.equals(method.getName())) {
+ Class>[] paramTypes = method.getParameterTypes();
+ if (paramTypes.length == 1
+ && paramTypes[0].getName().endsWith("Event")) { //$NON-NLS-1$
+ result = method;
+ break;
+ }
+
+ }
+ }
+ if (null == result) {
+ throw new IntrospectionException(Messages.getString("custom.beans.31", //$NON-NLS-1$
+ listenerMethodName, listenerType.getName()));
+ }
+ return result;
+ }
+
+ public EventSetDescriptor(String eventSetName, Class> listenerType,
+ Method[] listenerMethods, Method addListenerMethod,
+ Method removeListenerMethod) throws IntrospectionException {
+
+ this(eventSetName, listenerType, listenerMethods, addListenerMethod,
+ removeListenerMethod, null);
+ }
+
+ public EventSetDescriptor(String eventSetName, Class> listenerType,
+ Method[] listenerMethods, Method addListenerMethod,
+ Method removeListenerMethod, Method getListenerMethod)
+ throws IntrospectionException {
+
+ setName(eventSetName);
+ this.listenerType = listenerType;
+
+ this.listenerMethods = listenerMethods;
+ if (listenerMethods != null) {
+ listenerMethodDescriptors = new ArrayList();
+
+ for (Method element : listenerMethods) {
+ // XXX do we need this check?
+ // checkEventType(eventSetName, element);
+ // if (checkMethod(listenerType, element)) {
+ this.listenerMethodDescriptors
+ .add(new MethodDescriptor(element));
+ // }
+ }
+ }
+
+ this.addListenerMethod = addListenerMethod;
+ this.removeListenerMethod = removeListenerMethod;
+ this.getListenerMethod = getListenerMethod;
+ this.unicast = isUnicastByDefault(addListenerMethod);
+ }
+
+ public EventSetDescriptor(String eventSetName, Class> listenerType,
+ MethodDescriptor[] listenerMethodDescriptors,
+ Method addListenerMethod, Method removeListenerMethod)
+ throws IntrospectionException {
+
+ this(eventSetName, listenerType, null, addListenerMethod,
+ removeListenerMethod, null);
+
+ if (listenerMethodDescriptors != null) {
+ this.listenerMethodDescriptors = new ArrayList();
+
+ for (MethodDescriptor element : listenerMethodDescriptors) {
+ this.listenerMethodDescriptors.add(element);
+ }
+ }
+ }
+
+ // ensures that there is no nulls
+ @SuppressWarnings("nls")
+ private void checkNotNull(Object sourceClass, Object eventSetName,
+ Object alistenerType, Object listenerMethodName) {
+ if (sourceClass == null) {
+ throw new NullPointerException(Messages.getString("custom.beans.0C"));
+ }
+ if (eventSetName == null) {
+ throw new NullPointerException(Messages.getString("custom.beans.53"));
+ }
+ if (alistenerType == null) {
+ throw new NullPointerException(Messages.getString("custom.beans.54"));
+ }
+ if (listenerMethodName == null) {
+ throw new NullPointerException(Messages.getString("custom.beans.52"));
+ }
+ }
+
+ /**
+ * Checks that given listener method has an argument of the valid type.
+ *
+ * @param eventSetName
+ * event set name
+ * @param listenerMethod
+ * listener method
+ * @throws IntrospectionException
+ * if check fails
+ */
+ private static void checkEventType(String eventSetName,
+ Method listenerMethod) throws IntrospectionException {
+ Class>[] params = listenerMethod.getParameterTypes();
+ String firstParamTypeName = null;
+ String eventTypeName = prepareEventTypeName(eventSetName);
+
+ if (params.length > 0) {
+ firstParamTypeName = extractShortClassName(params[0]
+ .getName());
+ }
+
+ if (firstParamTypeName == null
+ || !firstParamTypeName.equals(eventTypeName)) {
+ throw new IntrospectionException(Messages.getString("custom.beans.51", //$NON-NLS-1$
+ listenerMethod.getName(), eventTypeName));
+ }
+ }
+
+ /**
+ * @param fullClassName full name of the class
+ * @return name with package and encapsulating class info omitted
+ */
+ private static String extractShortClassName(String fullClassName) {
+ int k = fullClassName.lastIndexOf('$');
+ k = (k == -1 ? fullClassName.lastIndexOf('.') : k);
+ return fullClassName.substring(k + 1);
+ }
+
+ private static String prepareEventTypeName(String eventSetName) {
+ StringBuilder sb = new StringBuilder();
+
+ if (eventSetName != null && eventSetName.length() > 0) {
+ sb.append(Character.toUpperCase(eventSetName.charAt(0)));
+
+ if (eventSetName.length() > 1) {
+ sb.append(eventSetName.substring(1));
+ }
+ }
+
+ sb.append("Event"); //$NON-NLS-1$
+ return sb.toString();
+ }
+
+ public Method[] getListenerMethods() {
+ if (listenerMethods != null) {
+ return listenerMethods;
+ }
+
+ if (listenerMethodDescriptors != null) {
+ listenerMethods = new Method[listenerMethodDescriptors.size()];
+ int index = 0;
+ for (MethodDescriptor md : listenerMethodDescriptors) {
+ listenerMethods[index++] = md.getMethod();
+ }
+ return listenerMethods;
+ }
+ return null;
+ }
+
+ public MethodDescriptor[] getListenerMethodDescriptors() {
+ return listenerMethodDescriptors == null ? null
+ : listenerMethodDescriptors.toArray(new MethodDescriptor[0]);
+ }
+
+ public Method getRemoveListenerMethod() {
+ return removeListenerMethod;
+ }
+
+ public Method getGetListenerMethod() {
+ return getListenerMethod;
+ }
+
+ public Method getAddListenerMethod() {
+ return addListenerMethod;
+ }
+
+ public Class> getListenerType() {
+ return listenerType;
+ }
+
+ public void setUnicast(boolean unicast) {
+ this.unicast = unicast;
+ }
+
+ public void setInDefaultEventSet(boolean inDefaultEventSet) {
+ this.inDefaultEventSet = inDefaultEventSet;
+ }
+
+ public boolean isUnicast() {
+ return unicast;
+ }
+
+ public boolean isInDefaultEventSet() {
+ return inDefaultEventSet;
+ }
+
+ /**
+ * Searches for {add|remove}Listener methods in the event source. Parameter
+ * check is also performed.
+ *
+ * @param sourceClass
+ * event source class
+ * @param methodName
+ * method name to search
+ * @return found method
+ * @throws IntrospectionException
+ * if no valid method found
+ */
+ private Method findAddRemoveListenerMethod(Class> sourceClass,
+ String methodName) throws IntrospectionException {
+ try {
+ return sourceClass.getMethod(methodName, listenerType);
+ } catch (NoSuchMethodException e) {
+ return findAddRemoveListnerMethodWithLessCheck(sourceClass,
+ methodName);
+ } catch (Exception e) {
+ throw new IntrospectionException(Messages.getString("custom.beans.31", //$NON-NLS-1$
+ methodName, listenerType.getName()));
+ }
+ }
+
+ private Method findAddRemoveListnerMethodWithLessCheck(
+ Class> sourceClass, String methodName)
+ throws IntrospectionException {
+ Method[] methods = sourceClass.getMethods();
+ Method result = null;
+ for (Method method : methods) {
+ if (method.getName().equals(methodName)) {
+ Class>[] paramTypes = method.getParameterTypes();
+ if (paramTypes.length == 1) {
+ result = method;
+ break;
+ }
+ }
+ }
+ if (null == result) {
+ throw new IntrospectionException(Messages.getString("custom.beans.31", //$NON-NLS-1$
+ methodName, listenerType.getName()));
+ }
+ return result;
+ }
+
+ /**
+ * @param sourceClass
+ * class of event source
+ * @param methodName
+ * name of the custom getListeners() method
+ * @return found Method object for custom getListener or null if nothing is
+ * found
+ */
+ private Method findGetListenerMethod(Class> sourceClass, String methodName) {
+ try {
+ return sourceClass.getMethod(methodName);
+ } catch (Exception e) {
+ // RI keeps silence here and just returns null
+ return null;
+ }
+ }
+
+ private Method findMethodByPrefix(Class> sourceClass, String prefix,
+ String postfix) {
+ String shortName = listenerType.getName();
+ if (listenerType.getPackage() != null) {
+ shortName = shortName.substring(listenerType.getPackage().getName()
+ .length() + 1);
+ }
+ String methodName = prefix + shortName + postfix;
+ try {
+ if ("get".equals(prefix)) { //$NON-NLS-1$
+ return sourceClass.getMethod(methodName);
+ }
+ } catch (NoSuchMethodException nsme) {
+ return null;
+ }
+ Method[] methods = sourceClass.getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ if (methods[i].getName().equals(methodName)) {
+ Class>[] paramTypes = methods[i].getParameterTypes();
+ if (paramTypes.length == 1) {
+ return methods[i];
+ }
+ }
+ }
+ return null;
+ }
+
+ private static boolean isUnicastByDefault(Method addMethod) {
+ if (addMethod != null) {
+ Class>[] exceptionTypes = addMethod.getExceptionTypes();
+ for (Class> element : exceptionTypes) {
+ if (element.equals(TooManyListenersException.class)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ void merge(EventSetDescriptor event) {
+ super.merge(event);
+ if (addListenerMethod == null) {
+ addListenerMethod = event.addListenerMethod;
+ }
+ if (getListenerMethod == null) {
+ getListenerMethod = event.getListenerMethod;
+ }
+ if (listenerMethodDescriptors == null) {
+ listenerMethodDescriptors = event.listenerMethodDescriptors;
+ }
+ if (listenerMethods == null) {
+ listenerMethods = event.listenerMethods;
+ }
+ if (listenerType == null) {
+ listenerType = event.listenerType;
+ }
+
+ if (removeListenerMethod == null) {
+ removeListenerMethod = event.removeListenerMethod;
+ }
+ inDefaultEventSet &= event.inDefaultEventSet;
+ }
+}
diff --git a/src/main/java/custom/beans/ExceptionListener.java b/src/main/java/custom/beans/ExceptionListener.java
new file mode 100644
index 000000000..390ba4326
--- /dev/null
+++ b/src/main/java/custom/beans/ExceptionListener.java
@@ -0,0 +1,23 @@
+/* MODIFIED FOR THE MSGPACK PROJECT
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package custom.beans;
+
+public interface ExceptionListener {
+
+ public void exceptionThrown(Exception e);
+}
diff --git a/src/main/java/custom/beans/Expression.java b/src/main/java/custom/beans/Expression.java
new file mode 100644
index 000000000..aaddf09b4
--- /dev/null
+++ b/src/main/java/custom/beans/Expression.java
@@ -0,0 +1,72 @@
+/* MODIFIED FOR THE MSGPACK PROJECT
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package custom.beans;
+
+import org.apache.harmony.beans.BeansUtils;
+
+public class Expression extends Statement {
+
+ boolean valueIsDefined = false;
+
+ Object value;
+
+ public Expression(Object value, Object target, String methodName,
+ Object[] arguments) {
+ super(target, methodName, arguments);
+ this.value = value;
+ this.valueIsDefined = true;
+ }
+
+ public Expression(Object target, String methodName, Object[] arguments) {
+ super(target, methodName, arguments);
+ this.value = null;
+ this.valueIsDefined = false;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ if (!valueIsDefined) {
+ sb.append(""); //$NON-NLS-1$
+ } else {
+ if (value == null) {
+ sb.append(BeansUtils.NULL);
+ } else {
+ Class> clazz = value.getClass();
+ sb.append(clazz == String.class ? BeansUtils.QUOTE : BeansUtils
+ .idOfClass(clazz));
+ }
+ }
+ sb.append('=');
+ sb.append(super.toString());
+ return sb.toString();
+ }
+
+ public void setValue(Object value) {
+ this.value = value;
+ this.valueIsDefined = true;
+ }
+
+ public Object getValue() throws Exception {
+ if (!valueIsDefined) {
+ value = invokeMethod();
+ valueIsDefined = true;
+ }
+ return value;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/custom/beans/FeatureDescriptor.java b/src/main/java/custom/beans/FeatureDescriptor.java
new file mode 100644
index 000000000..4a4612939
--- /dev/null
+++ b/src/main/java/custom/beans/FeatureDescriptor.java
@@ -0,0 +1,249 @@
+/* MODIFIED FOR THE MSGPACK PROJECT
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package custom.beans;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+/**
+ * Common base class for Descriptors.
+ */
+public class FeatureDescriptor {
+
+ private Map values;
+
+ boolean preferred, hidden, expert;
+
+ String shortDescription;
+
+ String name;
+
+ String displayName;
+
+ /**
+ *
+ * Constructs an instance.
+ *
+ */
+ public FeatureDescriptor() {
+ this.values = new HashMap();
+ }
+
+ /**
+ *
+ * Sets the value for the named attribute.
+ *
+ *
+ * @param attributeName
+ * The name of the attribute to set a value with.
+ * @param value
+ * The value to set.
+ */
+ public void setValue(String attributeName, Object value) {
+ if (attributeName == null || value == null) {
+ throw new NullPointerException();
+ }
+ values.put(attributeName, value);
+ }
+
+ /**
+ *
+ * Gets the value associated with the named attribute.
+ *
+ *
+ * @param attributeName
+ * The name of the attribute to get a value for.
+ * @return The attribute's value.
+ */
+ public Object getValue(String attributeName) {
+ if (attributeName != null) {
+ return values.get(attributeName);
+ }
+ return null;
+ }
+
+ /**
+ *
+ * Enumerates the attribute names.
+ *
+ *
+ * @return An instance of {@link Enumeration}.
+ */
+ public Enumeration attributeNames() {
+ // Create a new list, so that the references are copied
+ return Collections.enumeration(new LinkedList(values.keySet()));
+ }
+
+ /**
+ *
+ * Sets the short description.
+ *
+ *
+ * @param text
+ * The description to set.
+ */
+ public void setShortDescription(String text) {
+ this.shortDescription = text;
+ }
+
+ /**
+ *
+ * Sets the name.
+ *
+ *
+ * @param name
+ * The name to set.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ *
+ * Sets the display name.
+ *
+ *
+ * @param displayName
+ * The display name to set.
+ */
+ public void setDisplayName(String displayName) {
+ this.displayName = displayName;
+ }
+
+ /**
+ *
+ * Gets the short description or {@link #getDisplayName()} if not set.
+ *
+ * Indicates if this feature is an expert feature.
+ *
+ *
+ * @return true if hidden, false otherwise.
+ */
+ public boolean isExpert() {
+ return expert;
+ }
+
+ void merge(FeatureDescriptor feature){
+ assert(name.equals(feature.name));
+ expert |= feature.expert;
+ hidden |= feature.hidden;
+ preferred |= feature.preferred;
+ if(shortDescription == null){
+ shortDescription = feature.shortDescription;
+ }
+ if(name == null){
+ name = feature.name;
+ }
+ if(displayName == null){
+ displayName = feature.displayName;
+ }
+ }
+}
diff --git a/src/main/java/custom/beans/IndexedPropertyDescriptor.java b/src/main/java/custom/beans/IndexedPropertyDescriptor.java
new file mode 100644
index 000000000..57946b6db
--- /dev/null
+++ b/src/main/java/custom/beans/IndexedPropertyDescriptor.java
@@ -0,0 +1,383 @@
+/* MODIFIED FOR THE MSGPACK PROJECT
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package custom.beans;
+
+import java.lang.reflect.Method;
+
+import org.apache.harmony.beans.BeansUtils;
+import org.apache.harmony.beans.internal.nls.Messages;
+
+public class IndexedPropertyDescriptor extends PropertyDescriptor {
+
+ private Class> indexedPropertyType;
+
+ private Method indexedGetter;
+
+ private Method indexedSetter;
+
+ /**
+ * Constructs a new instance of IndexedPropertyDescriptor.
+ *
+ * @param propertyName
+ * the specified indexed property's name.
+ * @param beanClass
+ * the bean class
+ * @param getterName
+ * the name of the array getter
+ * @param setterName
+ * the name of the array setter
+ * @param indexedGetterName
+ * the name of the indexed getter.
+ * @param indexedSetterName
+ * the name of the indexed setter.
+ * @throws IntrospectionException
+ */
+ public IndexedPropertyDescriptor(String propertyName, Class> beanClass,
+ String getterName, String setterName, String indexedGetterName,
+ String indexedSetterName) throws IntrospectionException {
+ super(propertyName, beanClass, getterName, setterName);
+ setIndexedByName(beanClass, indexedGetterName, indexedSetterName);
+ }
+
+ private void setIndexedByName(Class> beanClass, String indexedGetterName,
+ String indexedSetterName) throws IntrospectionException {
+
+ String theIndexedGetterName = indexedGetterName;
+ if (theIndexedGetterName == null) {
+ if (indexedSetterName != null) {
+ setIndexedWriteMethod(beanClass, indexedSetterName);
+ }
+ } else {
+ if (theIndexedGetterName.length() == 0) {
+ theIndexedGetterName = "get" + name; //$NON-NLS-1$
+ }
+ setIndexedReadMethod(beanClass, theIndexedGetterName);
+ if (indexedSetterName != null) {
+ setIndexedWriteMethod(beanClass, indexedSetterName,
+ indexedPropertyType);
+ }
+ }
+
+ if (!isCompatible()) {
+ // custom.beans.57=Property type is incompatible with the indexed property type
+ throw new IntrospectionException(Messages.getString("custom.beans.57")); //$NON-NLS-1$
+ }
+ }
+
+ private boolean isCompatible() {
+ Class> propertyType = getPropertyType();
+
+ if (propertyType == null) {
+ return true;
+ }
+ Class> componentTypeOfProperty = propertyType.getComponentType();
+ if (componentTypeOfProperty == null) {
+ return false;
+ }
+ if (indexedPropertyType == null) {
+ return false;
+ }
+
+ return componentTypeOfProperty.getName().equals(
+ indexedPropertyType.getName());
+ }
+
+ /**
+ * Constructs a new instance of IndexedPropertyDescriptor.
+ *
+ * @param propertyName
+ * the specified indexed property's name.
+ * @param getter
+ * the array getter
+ * @param setter
+ * the array setter
+ * @param indexedGetter
+ * the indexed getter
+ * @param indexedSetter
+ * the indexed setter
+ * @throws IntrospectionException
+ */
+ public IndexedPropertyDescriptor(String propertyName, Method getter,
+ Method setter, Method indexedGetter, Method indexedSetter)
+ throws IntrospectionException {
+ super(propertyName, getter, setter);
+ if (indexedGetter != null) {
+ internalSetIndexedReadMethod(indexedGetter);
+ internalSetIndexedWriteMethod(indexedSetter, true);
+ } else {
+ internalSetIndexedWriteMethod(indexedSetter, true);
+ internalSetIndexedReadMethod(indexedGetter);
+ }
+
+ if (!isCompatible()) {
+ // custom.beans.57=Property type is incompatible with the indexed property type
+ throw new IntrospectionException(Messages.getString("custom.beans.57")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Constructs a new instance of IndexedPropertyDescriptor.
+ *
+ * @param propertyName
+ * the specified indexed property's name.
+ * @param beanClass
+ * the bean class.
+ * @throws IntrospectionException
+ */
+ public IndexedPropertyDescriptor(String propertyName, Class> beanClass)
+ throws IntrospectionException {
+ super(propertyName, beanClass);
+ setIndexedByName(beanClass, "get" //$NON-NLS-1$
+ .concat(initialUpperCase(propertyName)), "set" //$NON-NLS-1$
+ .concat(initialUpperCase(propertyName)));
+ }
+
+ /**
+ * Sets the indexed getter as the specified method.
+ *
+ * @param indexedGetter
+ * the specified indexed getter.
+ * @throws IntrospectionException
+ */
+ public void setIndexedReadMethod(Method indexedGetter)
+ throws IntrospectionException {
+ this.internalSetIndexedReadMethod(indexedGetter);
+ }
+
+ /**
+ * Sets the indexed setter as the specified method.
+ *
+ * @param indexedSetter
+ * the specified indexed setter.
+ * @throws IntrospectionException
+ */
+ public void setIndexedWriteMethod(Method indexedSetter)
+ throws IntrospectionException {
+ this.internalSetIndexedWriteMethod(indexedSetter, false);
+ }
+
+ /**
+ * Obtains the indexed setter.
+ *
+ * @return the indexed setter.
+ */
+ public Method getIndexedWriteMethod() {
+ return indexedSetter;
+ }
+
+ /**
+ * Obtains the indexed getter.
+ *
+ * @return the indexed getter.
+ */
+ public Method getIndexedReadMethod() {
+ return indexedGetter;
+ }
+
+ /**
+ * Determines if this IndexedPropertyDescriptor is equal to
+ * the specified object. Two IndexedPropertyDescriptor s are
+ * equal if the reader, indexed reader, writer, indexed writer, property
+ * types, indexed property type, property editor and flags are equal.
+ *
+ * @param obj
+ * @return true if this indexed property descriptor is equal to the
+ * specified object.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof IndexedPropertyDescriptor)) {
+ return false;
+ }
+
+ IndexedPropertyDescriptor other = (IndexedPropertyDescriptor) obj;
+
+ return (super.equals(other)
+ && (indexedPropertyType == null ? other.indexedPropertyType == null
+ : indexedPropertyType.equals(other.indexedPropertyType))
+ && (indexedGetter == null ? other.indexedGetter == null
+ : indexedGetter.equals(other.indexedGetter)) && (indexedSetter == null ? other.indexedSetter == null
+ : indexedSetter.equals(other.indexedSetter)));
+ }
+
+ /**
+ * HashCode of the IndexedPropertyDescriptor
+ */
+ @Override
+ public int hashCode() {
+ return super.hashCode() + BeansUtils.getHashCode(indexedPropertyType)
+ + BeansUtils.getHashCode(indexedGetter)
+ + BeansUtils.getHashCode(indexedSetter);
+ }
+
+ /**
+ * Obtains the Class object of the indexed property type.
+ *
+ * @return the Class object of the indexed property type.
+ */
+ public Class> getIndexedPropertyType() {
+ return indexedPropertyType;
+ }
+
+ private void setIndexedReadMethod(Class> beanClass, String indexedGetterName)
+ throws IntrospectionException {
+ Method getter;
+ try {
+ getter = beanClass.getMethod(indexedGetterName,
+ new Class[] { Integer.TYPE });
+ } catch (NoSuchMethodException exception) {
+ // custom.beans.58=No such indexed read method
+ throw new IntrospectionException(Messages.getString("custom.beans.58")); //$NON-NLS-1$
+ } catch (SecurityException exception) {
+ // custom.beans.59=Security violation accessing indexed read method
+ throw new IntrospectionException(Messages.getString("custom.beans.59")); //$NON-NLS-1$
+ }
+ internalSetIndexedReadMethod(getter);
+ }
+
+ private void internalSetIndexedReadMethod(Method indexGetter)
+ throws IntrospectionException {
+ // Clearing the indexed read method.
+ if (indexGetter == null) {
+ if (indexedSetter == null) {
+ if (getPropertyType() != null) {
+ // custom.beans.5A=Indexed method is not compatible with non indexed method
+ throw new IntrospectionException(Messages
+ .getString("custom.beans.5A")); //$NON-NLS-1$
+ }
+ indexedPropertyType = null;
+ }
+ this.indexedGetter = null;
+ return;
+ }
+ // Validate the indexed getter.
+ if ((indexGetter.getParameterTypes().length != 1)
+ || (indexGetter.getParameterTypes()[0] != Integer.TYPE)) {
+ // custom.beans.5B=Indexed read method must take a single int argument
+ throw new IntrospectionException(Messages.getString("custom.beans.5B")); //$NON-NLS-1$
+ }
+ Class> indexedReadType = indexGetter.getReturnType();
+ if (indexedReadType == Void.TYPE) {
+ // custom.beans.5B=Indexed read method must take a single int argument
+ throw new IntrospectionException(Messages.getString("custom.beans.5B")); //$NON-NLS-1$
+ } else if (indexedSetter != null
+ && indexGetter.getReturnType() != indexedSetter
+ .getParameterTypes()[1]) {
+ // custom.beans.5A=Indexed read method is not compatible with indexed write method
+ throw new IntrospectionException(Messages.getString("custom.beans.5A")); //$NON-NLS-1$
+ }
+
+ // Set the indexed property type if not already set, confirm validity if
+ // it is.
+ if (this.indexedGetter == null) {
+ indexedPropertyType = indexedReadType;
+ } else {
+ if (indexedPropertyType != indexedReadType) {
+ // custom.beans.5A=Indexed read method is not compatible with indexed write method
+ throw new IntrospectionException(Messages.getString("custom.beans.5A")); //$NON-NLS-1$
+ }
+ }
+
+ // Set the indexed getter
+ this.indexedGetter = indexGetter;
+ }
+
+ private void setIndexedWriteMethod(Class> beanClass, String indexedSetterName)
+ throws IntrospectionException {
+ Method setter = null;
+ try {
+ setter = beanClass.getMethod(indexedSetterName, new Class[] {
+ Integer.TYPE, getPropertyType().getComponentType() });
+ } catch (SecurityException e) {
+ // custom.beans.5C=Security violation accessing indexed write method
+ throw new IntrospectionException(Messages.getString("custom.beans.5C")); //$NON-NLS-1$
+ } catch (NoSuchMethodException e) {
+ // custom.beans.5D=No such indexed write method
+ throw new IntrospectionException(Messages.getString("custom.beans.5D")); //$NON-NLS-1$
+ }
+ internalSetIndexedWriteMethod(setter, true);
+ }
+
+ private void setIndexedWriteMethod(Class> beanClass,
+ String indexedSetterName, Class> argType)
+ throws IntrospectionException {
+ try {
+ Method setter = beanClass.getMethod(indexedSetterName, new Class[] {
+ Integer.TYPE, argType });
+ internalSetIndexedWriteMethod(setter, true);
+ } catch (NoSuchMethodException exception) {
+ // custom.beans.5D=No such indexed write method
+ throw new IntrospectionException(Messages.getString("custom.beans.5D")); //$NON-NLS-1$
+ } catch (SecurityException exception) {
+ // custom.beans.5C=Security violation accessing indexed write method
+ throw new IntrospectionException(Messages.getString("custom.beans.5C")); //$NON-NLS-1$
+ }
+ }
+
+ private void internalSetIndexedWriteMethod(Method indexSetter,
+ boolean initialize) throws IntrospectionException {
+ // Clearing the indexed write method.
+ if (indexSetter == null) {
+ if (indexedGetter == null) {
+ if (getPropertyType() != null) {
+ // custom.beans.5E=Indexed method is not compatible with non indexed method
+ throw new IntrospectionException(Messages
+ .getString("custom.beans.5E")); //$NON-NLS-1$
+ }
+ indexedPropertyType = null;
+ }
+ this.indexedSetter = null;
+ return;
+ }
+
+ // Validate the indexed write method.
+ Class>[] indexedSetterArgs = indexSetter.getParameterTypes();
+ if (indexedSetterArgs.length != 2) {
+ // custom.beans.5F=Indexed write method must take two arguments
+ throw new IntrospectionException(Messages.getString("custom.beans.5F")); //$NON-NLS-1$
+ }
+ if (indexedSetterArgs[0] != Integer.TYPE) {
+ // custom.beans.60=Indexed write method must take an int as its first argument
+ throw new IntrospectionException(Messages.getString("custom.beans.60")); //$NON-NLS-1$
+ }
+
+ // Set the indexed property type if not already set, confirm validity if
+ // it is.
+ Class> indexedWriteType = indexedSetterArgs[1];
+ if (initialize && indexedGetter == null) {
+ indexedPropertyType = indexedWriteType;
+ } else {
+ if (indexedPropertyType != indexedWriteType) {
+ // custom.beans.61=Indexed write method is not compatible with indexed read method
+ throw new IntrospectionException(Messages.getString("custom.beans.61")); //$NON-NLS-1$
+ }
+ }
+
+ // Set the indexed write method.
+ this.indexedSetter = indexSetter;
+ }
+
+ private static String initialUpperCase(String string) {
+ if (Character.isUpperCase(string.charAt(0))) {
+ return string;
+ }
+
+ String initial = string.substring(0, 1).toUpperCase();
+ return initial.concat(string.substring(1));
+ }
+}
diff --git a/src/main/java/custom/beans/IntrospectionException.java b/src/main/java/custom/beans/IntrospectionException.java
new file mode 100644
index 000000000..e75429ac8
--- /dev/null
+++ b/src/main/java/custom/beans/IntrospectionException.java
@@ -0,0 +1,27 @@
+/* MODIFIED FOR THE MSGPACK PROJECT
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package custom.beans;
+
+public class IntrospectionException extends Exception {
+
+ private static final long serialVersionUID = -3728150539969542619L;
+
+ public IntrospectionException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/custom/beans/Introspector.java b/src/main/java/custom/beans/Introspector.java
new file mode 100644
index 000000000..616bb44cb
--- /dev/null
+++ b/src/main/java/custom/beans/Introspector.java
@@ -0,0 +1,368 @@
+/* MODIFIED FOR THE MSGPACK PROJECT
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package custom.beans;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+/**
+ * The Introspector is a utility for developers to figure out
+ * which properties, events, and methods a JavaBean supports.
+ *
+ * The Introspector class walks over the class/superclass chain
+ * of the target bean class. At each level it checks if there is a matching
+ * BeanInfo class which provides explicit information about the
+ * bean, and if so uses that explicit information. Otherwise it uses the low
+ * level reflection APIs to study the target class and uses design patterns to
+ * analyze its behaviour and then proceeds to continue the introspection with
+ * its baseclass.
+ *
+ *
+ * To look for the explicit information of a bean:
+ *
+ *
+ *
The Introspector appends "BeanInfo" to the qualified name
+ * of the bean class, try to use the new class as the "BeanInfo" class. If the
+ * "BeanInfo" class exsits and returns non-null value when queried for explicit
+ * information, use the explicit information
+ *
If the first step fails, the Introspector will extract a
+ * simple class name of the bean class by removing the package name from the
+ * qualified name of the bean class, append "BeanInfo" to it. And look for the
+ * simple class name in the packages defined in the "BeanInfo" search path (The
+ * default "BeanInfo" search path is sun.beans.infos). If it
+ * finds a "BeanInfo" class and the "BeanInfo" class returns non-null value when
+ * queried for explicit information, use the explicit information
+ *
+ *
+ */
+//ScrollPane cannot be introspected correctly
+public class Introspector extends java.lang.Object {
+
+ // Public fields
+ /**
+ * Constant values to indicate that the Introspector will
+ * ignore all BeanInfo class.
+ */
+ public static final int IGNORE_ALL_BEANINFO = 3;
+
+ /**
+ * Constant values to indicate that the Introspector will
+ * ignore the BeanInfo class of the current bean class.
+ */
+ public static final int IGNORE_IMMEDIATE_BEANINFO = 2;
+
+ /**
+ * Constant values to indicate that the Introspector will use
+ * all BeanInfo class which have been found. This is the default one.
+ */
+ public static final int USE_ALL_BEANINFO = 1;
+
+ // Default search path for BeanInfo classes
+ private static final String DEFAULT_BEANINFO_SEARCHPATH = "sun.beans.infos"; //$NON-NLS-1$
+
+ // The search path to use to find BeanInfo classes
+ // - an array of package names that are used in turn
+ private static String[] searchPath = { DEFAULT_BEANINFO_SEARCHPATH };
+
+ // The cache to store Bean Info objects that have been found or created
+ private static final int DEFAULT_CAPACITY = 128;
+
+ private static Map, StandardBeanInfo> theCache = Collections.synchronizedMap(new WeakHashMap, StandardBeanInfo>(DEFAULT_CAPACITY));
+
+ private Introspector() {
+ super();
+ }
+
+ /**
+ * Decapitalizes a given string according to the rule:
+ *
+ *
If the first or only character is Upper Case, it is made Lower Case
+ *
UNLESS the second character is also Upper Case, when the String is
+ * returned unchanged
+ *
+ * @param name -
+ * the String to decapitalize
+ * @return the decapitalized version of the String
+ */
+ public static String decapitalize(String name) {
+
+ if (name == null)
+ return null;
+ // The rule for decapitalize is that:
+ // If the first letter of the string is Upper Case, make it lower case
+ // UNLESS the second letter of the string is also Upper Case, in which case no
+ // changes are made.
+ if (name.length() == 0 || (name.length() > 1 && Character.isUpperCase(name.charAt(1)))) {
+ return name;
+ }
+
+ char[] chars = name.toCharArray();
+ chars[0] = Character.toLowerCase(chars[0]);
+ return new String(chars);
+ }
+
+ /**
+ * Flushes all BeanInfo caches.
+ *
+ */
+ public static void flushCaches() {
+ // Flush the cache by throwing away the cache HashMap and creating a
+ // new empty one
+ theCache.clear();
+ }
+
+ /**
+ * Flushes the BeanInfo caches of the specified bean class
+ *
+ * @param clazz
+ * the specified bean class
+ */
+ public static void flushFromCaches(Class> clazz) {
+ if(clazz == null){
+ throw new NullPointerException();
+ }
+ theCache.remove(clazz);
+ }
+
+ /**
+ * Gets the BeanInfo object which contains the information of
+ * the properties, events and methods of the specified bean class.
+ *
+ *
+ * The Introspector will cache the BeanInfo
+ * object. Subsequent calls to this method will be answered with the cached
+ * data.
+ *
+ *
+ * @param beanClass
+ * the specified bean class.
+ * @return the BeanInfo of the bean class.
+ * @throws IntrospectionException
+ */
+ public static BeanInfo getBeanInfo(Class> beanClass)
+ throws IntrospectionException {
+ StandardBeanInfo beanInfo = theCache.get(beanClass);
+ if (beanInfo == null) {
+ beanInfo = getBeanInfoImplAndInit(beanClass, null, USE_ALL_BEANINFO);
+ theCache.put(beanClass, beanInfo);
+ }
+ return beanInfo;
+ }
+
+ /**
+ * Gets the BeanInfo object which contains the information of
+ * the properties, events and methods of the specified bean class. It will
+ * not introspect the "stopclass" and its super class.
+ *
+ *
+ * The Introspector will cache the BeanInfo
+ * object. Subsequent calls to this method will be answered with the cached
+ * data.
+ *
+ *
+ * @param beanClass
+ * the specified beanClass.
+ * @param stopClass
+ * the sopt class which should be super class of the bean class.
+ * May be null.
+ * @return the BeanInfo of the bean class.
+ * @throws IntrospectionException
+ */
+ public static BeanInfo getBeanInfo(Class> beanClass, Class> stopClass)
+ throws IntrospectionException {
+ if(stopClass == null){
+ //try to use cache
+ return getBeanInfo(beanClass);
+ }
+ return getBeanInfoImplAndInit(beanClass, stopClass, USE_ALL_BEANINFO);
+ }
+
+ /**
+ * Gets the BeanInfo object which contains the information of
+ * the properties, events and methods of the specified bean class.
+ *
+ *
If flag==IGNORE_ALL_BEANINFO, the
+ * Introspector will ignore all BeanInfo
+ * class.
+ *
If flag==IGNORE_IMMEDIATE_BEANINFO, the
+ * Introspector will ignore the BeanInfo class
+ * of the current bean class.
+ *
If flag==USE_ALL_BEANINFO, the
+ * Introspector will use all BeanInfo class
+ * which have been found.
+ *
+ *
+ * The Introspector will cache the BeanInfo
+ * object. Subsequent calls to this method will be answered with the cached
+ * data.
+ *
+ *
+ * @param beanClass
+ * the specified bean class.
+ * @param flags
+ * the flag to control the usage of the explicit
+ * BeanInfo class.
+ * @return the BeanInfo of the bean class.
+ * @throws IntrospectionException
+ */
+ public static BeanInfo getBeanInfo(Class> beanClass, int flags)
+ throws IntrospectionException {
+ if(flags == USE_ALL_BEANINFO){
+ //try to use cache
+ return getBeanInfo(beanClass);
+ }
+ return getBeanInfoImplAndInit(beanClass, null, flags);
+ }
+
+ /**
+ * Gets an array of search packages.
+ *
+ * @return an array of search packages.
+ */
+ public static String[] getBeanInfoSearchPath() {
+ String[] path = new String[searchPath.length];
+ System.arraycopy(searchPath, 0, path, 0, searchPath.length);
+ return path;
+ }
+
+ /**
+ * Sets the search packages.
+ *
+ * @param path the new search packages to be set.
+ */
+ public static void setBeanInfoSearchPath(String[] path) {
+ if (System.getSecurityManager() != null) {
+ System.getSecurityManager().checkPropertiesAccess();
+ }
+ searchPath = path;
+ }
+
+ private static StandardBeanInfo getBeanInfoImpl(Class> beanClass, Class> stopClass,
+ int flags) throws IntrospectionException {
+ BeanInfo explicitInfo = null;
+ if (flags == USE_ALL_BEANINFO) {
+ explicitInfo = getExplicitBeanInfo(beanClass);
+ }
+ StandardBeanInfo beanInfo = new StandardBeanInfo(beanClass, explicitInfo, stopClass);
+
+ if (beanInfo.additionalBeanInfo != null) {
+ for (int i = beanInfo.additionalBeanInfo.length-1; i >=0; i--) {
+ BeanInfo info = beanInfo.additionalBeanInfo[i];
+ beanInfo.mergeBeanInfo(info, true);
+ }
+ }
+
+ // recursive get beaninfo for super classes
+ Class> beanSuperClass = beanClass.getSuperclass();
+ if (beanSuperClass != stopClass) {
+ if (beanSuperClass == null)
+ throw new IntrospectionException(
+ "Stop class is not super class of bean class"); //$NON-NLS-1$
+ int superflags = flags == IGNORE_IMMEDIATE_BEANINFO ? USE_ALL_BEANINFO
+ : flags;
+ BeanInfo superBeanInfo = getBeanInfoImpl(beanSuperClass, stopClass,
+ superflags);
+ if (superBeanInfo != null) {
+ beanInfo.mergeBeanInfo(superBeanInfo, false);
+ }
+ }
+ return beanInfo;
+ }
+
+ private static BeanInfo getExplicitBeanInfo(Class> beanClass) {
+ String beanInfoClassName = beanClass.getName() + "BeanInfo"; //$NON-NLS-1$
+ try {
+ return loadBeanInfo(beanInfoClassName, beanClass);
+ } catch (Exception e) {
+ // fall through
+ }
+
+ int index = beanInfoClassName.lastIndexOf('.');
+ String beanInfoName = index >= 0 ? beanInfoClassName
+ .substring(index + 1) : beanInfoClassName;
+ BeanInfo theBeanInfo = null;
+ BeanDescriptor beanDescriptor = null;
+ for (int i = 0; i < searchPath.length; i++) {
+ beanInfoClassName = searchPath[i] + "." + beanInfoName; //$NON-NLS-1$
+ try {
+ theBeanInfo = loadBeanInfo(beanInfoClassName, beanClass);
+ } catch (Exception e) {
+ // ignore, try next one
+ continue;
+ }
+ beanDescriptor = theBeanInfo.getBeanDescriptor();
+ if (beanDescriptor != null
+ && beanClass == beanDescriptor.getBeanClass()) {
+ return theBeanInfo;
+ }
+ }
+ if (BeanInfo.class.isAssignableFrom(beanClass)) {
+ try {
+ return loadBeanInfo(beanClass.getName(), beanClass);
+ } catch (Exception e) {
+ // fall through
+ }
+ }
+ return null;
+ }
+
+ /* MODIFIED FOR THE MSGPACK PROJECT
+ * Method which attempts to instantiate a BeanInfo object of the supplied
+ * classname
+ *
+ * @param theBeanInfoClassName -
+ * the Class Name of the class of which the BeanInfo is an
+ * instance
+ * @param classLoader
+ * @return A BeanInfo object which is an instance of the Class named
+ * theBeanInfoClassName null if the Class does not exist or if there
+ * are problems instantiating the instance
+ */
+ private static BeanInfo loadBeanInfo(String beanInfoClassName,
+ Class> beanClass) throws Exception{
+ try {
+ ClassLoader cl = beanClass.getClassLoader();
+ if(cl != null){
+ return (BeanInfo) Class.forName(beanInfoClassName, true,
+ beanClass.getClassLoader()).newInstance();
+ }
+ } catch (Exception e) {
+ // fall through
+ }
+ try {
+ return (BeanInfo) Class.forName(beanInfoClassName, true,
+ ClassLoader.getSystemClassLoader()).newInstance();
+ } catch (Exception e) {
+ // fall through
+ }
+ return (BeanInfo) Class.forName(beanInfoClassName, true,
+ Thread.currentThread().getContextClassLoader()).newInstance();
+ }
+
+ private static StandardBeanInfo getBeanInfoImplAndInit(Class> beanClass,
+ Class> stopClass, int flag) throws IntrospectionException {
+ StandardBeanInfo standardBeanInfo = getBeanInfoImpl(beanClass,
+ stopClass, flag);
+ standardBeanInfo.init();
+ return standardBeanInfo;
+ }
+}
+
+
+
diff --git a/src/main/java/custom/beans/MethodDescriptor.java b/src/main/java/custom/beans/MethodDescriptor.java
new file mode 100644
index 000000000..1cb0aa40c
--- /dev/null
+++ b/src/main/java/custom/beans/MethodDescriptor.java
@@ -0,0 +1,109 @@
+/* MODIFIED FOR THE MSGPACK PROJECT
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package custom.beans;
+
+import java.lang.reflect.Method;
+
+/**
+ * Describes a bean's method.
+ */
+public class MethodDescriptor extends FeatureDescriptor {
+
+ private Method method;
+
+ private ParameterDescriptor[] parameterDescriptors;
+
+ /**
+ *
+ * Constructs an instance with the given {@link Method} and
+ * {@link ParameterDescriptor}s. The {@link #getName()} is set as the name
+ * of the method passed.
+ *
+ *
+ * @param method
+ * The Method to set.
+ * @param parameterDescriptors
+ * An array of parameter descriptors.
+ */
+ public MethodDescriptor(Method method,
+ ParameterDescriptor[] parameterDescriptors) {
+ super();
+
+ if (method == null) {
+ throw new NullPointerException();
+ }
+ this.method = method;
+ this.parameterDescriptors = parameterDescriptors;
+
+ setName(method.getName());
+ }
+
+ /**
+ *
+ * Constructs an instance with the given {@link Method}. The
+ * {@link #getName()} is set as the name of the method
+ * passed.
+ *
+ *
+ * @param method
+ * The Method to set.
+ */
+ public MethodDescriptor(Method method) {
+ super();
+
+ if (method == null) {
+ throw new NullPointerException();
+ }
+ this.method = method;
+
+ setName(method.getName());
+ }
+
+ /**
+ *
+ *
+ * @return An array of {@link ParameterDescriptor} instance or
+ * null.
+ */
+ public ParameterDescriptor[] getParameterDescriptors() {
+ return parameterDescriptors;
+ }
+
+ void merge(MethodDescriptor anotherMethod){
+ super.merge(anotherMethod);
+ if(method == null){
+ method = anotherMethod.method;
+ }
+ if(parameterDescriptors == null){
+ parameterDescriptors = anotherMethod.parameterDescriptors;
+ }
+ }
+}
diff --git a/src/main/java/custom/beans/ParameterDescriptor.java b/src/main/java/custom/beans/ParameterDescriptor.java
new file mode 100644
index 000000000..acd9a112c
--- /dev/null
+++ b/src/main/java/custom/beans/ParameterDescriptor.java
@@ -0,0 +1,25 @@
+/* MODIFIED FOR THE MSGPACK PROJECT
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package custom.beans;
+
+public class ParameterDescriptor extends FeatureDescriptor {
+
+ public ParameterDescriptor() {
+ // do nothing
+ }
+}
diff --git a/src/main/java/custom/beans/PropertyChangeEvent.java b/src/main/java/custom/beans/PropertyChangeEvent.java
new file mode 100644
index 000000000..d0edc4a47
--- /dev/null
+++ b/src/main/java/custom/beans/PropertyChangeEvent.java
@@ -0,0 +1,62 @@
+/* MODIFIED FOR THE MSGPACK PROJECT
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package custom.beans;
+
+import java.util.EventObject;
+
+public class PropertyChangeEvent extends EventObject {
+
+ private static final long serialVersionUID = 7042693688939648123L;
+
+ String propertyName;
+
+ Object oldValue;
+
+ Object newValue;
+
+ Object propagationId;
+
+ public PropertyChangeEvent(Object source, String propertyName,
+ Object oldValue, Object newValue) {
+ super(source);
+
+ this.propertyName = propertyName;
+ this.oldValue = oldValue;
+ this.newValue = newValue;
+ }
+
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+ public void setPropagationId(Object propagationId) {
+ this.propagationId = propagationId;
+ }
+
+ public Object getPropagationId() {
+ return propagationId;
+ }
+
+ public Object getOldValue() {
+ return oldValue;
+ }
+
+ public Object getNewValue() {
+ return newValue;
+ }
+}
diff --git a/src/main/java/custom/beans/PropertyChangeListener.java b/src/main/java/custom/beans/PropertyChangeListener.java
new file mode 100644
index 000000000..42fa22b17
--- /dev/null
+++ b/src/main/java/custom/beans/PropertyChangeListener.java
@@ -0,0 +1,25 @@
+/* MODIFIED FOR THE MSGPACK PROJECT
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package custom.beans;
+
+import java.util.EventListener;
+
+public interface PropertyChangeListener extends EventListener {
+
+ public void propertyChange(PropertyChangeEvent event);
+}
diff --git a/src/main/java/custom/beans/PropertyDescriptor.java b/src/main/java/custom/beans/PropertyDescriptor.java
new file mode 100644
index 000000000..b009045f0
--- /dev/null
+++ b/src/main/java/custom/beans/PropertyDescriptor.java
@@ -0,0 +1,300 @@
+/* MODIFIED FOR THE MSGPACK PROJECT
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package custom.beans;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import org.apache.harmony.beans.BeansUtils;
+import org.apache.harmony.beans.internal.nls.Messages;
+
+public class PropertyDescriptor extends FeatureDescriptor {
+ private Method getter;
+
+ private Method setter;
+
+ private Class> propertyEditorClass;
+
+ boolean constrained;
+
+ boolean bound;
+
+ public PropertyDescriptor(String propertyName, Class> beanClass,
+ String getterName, String setterName) throws IntrospectionException {
+ super();
+ if (beanClass == null) {
+ throw new IntrospectionException(Messages.getString("custom.beans.03")); //$NON-NLS-1$
+ }
+ if (propertyName == null || propertyName.length() == 0) {
+ throw new IntrospectionException(Messages.getString("custom.beans.04")); //$NON-NLS-1$
+ }
+ this.setName(propertyName);
+ if (getterName != null) {
+ if (getterName.length() == 0) {
+ throw new IntrospectionException(
+ "read or write method cannot be empty."); //$NON-NLS-1$
+ }
+ try {
+ setReadMethod(beanClass, getterName);
+ } catch (IntrospectionException e) {
+ setReadMethod(beanClass, createDefaultMethodName(propertyName,
+ "get")); //$NON-NLS-1$
+ }
+ }
+ if (setterName != null) {
+ if (setterName.length() == 0) {
+ throw new IntrospectionException(
+ "read or write method cannot be empty."); //$NON-NLS-1$
+ }
+ setWriteMethod(beanClass, setterName);
+ }
+ }
+
+ public PropertyDescriptor(String propertyName, Method getter, Method setter)
+ throws IntrospectionException {
+ super();
+ if (propertyName == null || propertyName.length() == 0) {
+ throw new IntrospectionException(Messages.getString("custom.beans.04")); //$NON-NLS-1$
+ }
+ this.setName(propertyName);
+ setReadMethod(getter);
+ setWriteMethod(setter);
+ }
+
+ public PropertyDescriptor(String propertyName, Class> beanClass)
+ throws IntrospectionException {
+ if (beanClass == null) {
+ throw new IntrospectionException(Messages.getString("custom.beans.03")); //$NON-NLS-1$
+ }
+ if (propertyName == null || propertyName.length() == 0) {
+ throw new IntrospectionException(Messages.getString("custom.beans.04")); //$NON-NLS-1$
+ }
+ this.setName(propertyName);
+ try {
+ setReadMethod(beanClass,
+ createDefaultMethodName(propertyName, "is")); //$NON-NLS-1$
+ } catch (Exception e) {
+ setReadMethod(beanClass, createDefaultMethodName(propertyName,
+ "get")); //$NON-NLS-1$
+ }
+
+ setWriteMethod(beanClass, createDefaultMethodName(propertyName, "set")); //$NON-NLS-1$
+ }
+
+ public void setWriteMethod(Method setter) throws IntrospectionException {
+ if (setter != null) {
+ int modifiers = setter.getModifiers();
+ if (!Modifier.isPublic(modifiers)) {
+ throw new IntrospectionException(Messages.getString("custom.beans.05")); //$NON-NLS-1$
+ }
+ Class>[] parameterTypes = setter.getParameterTypes();
+ if (parameterTypes.length != 1) {
+ throw new IntrospectionException(Messages.getString("custom.beans.06")); //$NON-NLS-1$
+ }
+ Class> parameterType = parameterTypes[0];
+ Class> propertyType = getPropertyType();
+ if (propertyType != null && !propertyType.equals(parameterType)) {
+ throw new IntrospectionException(Messages.getString("custom.beans.07")); //$NON-NLS-1$
+ }
+ }
+ this.setter = setter;
+ }
+
+ public void setReadMethod(Method getter) throws IntrospectionException {
+ if (getter != null) {
+ int modifiers = getter.getModifiers();
+ if (!Modifier.isPublic(modifiers)) {
+ throw new IntrospectionException(Messages.getString("custom.beans.0A")); //$NON-NLS-1$
+ }
+ Class>[] parameterTypes = getter.getParameterTypes();
+ if (parameterTypes.length != 0) {
+ throw new IntrospectionException(Messages.getString("custom.beans.08")); //$NON-NLS-1$
+ }
+ Class> returnType = getter.getReturnType();
+ if (returnType.equals(Void.TYPE)) {
+ throw new IntrospectionException(Messages.getString("custom.beans.33")); //$NON-NLS-1$
+ }
+ Class> propertyType = getPropertyType();
+ if ((propertyType != null) && !returnType.equals(propertyType)) {
+ throw new IntrospectionException(Messages.getString("custom.beans.09")); //$NON-NLS-1$
+ }
+ }
+ this.getter = getter;
+ }
+
+ public Method getWriteMethod() {
+ return setter;
+ }
+
+ public Method getReadMethod() {
+ return getter;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ boolean result = object instanceof PropertyDescriptor;
+ if (result) {
+ PropertyDescriptor pd = (PropertyDescriptor) object;
+ boolean gettersAreEqual = (this.getter == null)
+ && (pd.getReadMethod() == null) || (this.getter != null)
+ && (this.getter.equals(pd.getReadMethod()));
+ boolean settersAreEqual = (this.setter == null)
+ && (pd.getWriteMethod() == null) || (this.setter != null)
+ && (this.setter.equals(pd.getWriteMethod()));
+ boolean propertyTypesAreEqual = this.getPropertyType() == pd
+ .getPropertyType();
+ boolean propertyEditorClassesAreEqual = this
+ .getPropertyEditorClass() == pd.getPropertyEditorClass();
+ boolean boundPropertyAreEqual = this.isBound() == pd.isBound();
+ boolean constrainedPropertyAreEqual = this.isConstrained() == pd
+ .isConstrained();
+ result = gettersAreEqual && settersAreEqual
+ && propertyTypesAreEqual && propertyEditorClassesAreEqual
+ && boundPropertyAreEqual && constrainedPropertyAreEqual;
+ }
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ return BeansUtils.getHashCode(getter) + BeansUtils.getHashCode(setter)
+ + BeansUtils.getHashCode(getPropertyType())
+ + BeansUtils.getHashCode(getPropertyEditorClass())
+ + BeansUtils.getHashCode(isBound())
+ + BeansUtils.getHashCode(isConstrained());
+ }
+
+ public void setPropertyEditorClass(Class> propertyEditorClass) {
+ this.propertyEditorClass = propertyEditorClass;
+ }
+
+ public Class> getPropertyType() {
+ Class> result = null;
+ if (getter != null) {
+ result = getter.getReturnType();
+ } else if (setter != null) {
+ Class>[] parameterTypes = setter.getParameterTypes();
+ result = parameterTypes[0];
+ }
+ return result;
+ }
+
+ public Class> getPropertyEditorClass() {
+ return propertyEditorClass;
+ }
+
+ public void setConstrained(boolean constrained) {
+ this.constrained = constrained;
+ }
+
+ public void setBound(boolean bound) {
+ this.bound = bound;
+ }
+
+ public boolean isConstrained() {
+ return constrained;
+ }
+
+ public boolean isBound() {
+ return bound;
+ }
+
+ String createDefaultMethodName(String propertyName, String prefix) {
+ String result = null;
+ if (propertyName != null) {
+ String bos = BeansUtils.toASCIIUpperCase(propertyName.substring(0, 1));
+ String eos = propertyName.substring(1, propertyName.length());
+ result = prefix + bos + eos;
+ }
+ return result;
+ }
+
+ void setReadMethod(Class> beanClass, String getterName)
+ throws IntrospectionException {
+ try {
+ Method readMethod = beanClass.getMethod(getterName, new Class[] {});
+ setReadMethod(readMethod);
+ } catch (Exception e) {
+ throw new IntrospectionException(e.getLocalizedMessage());
+ }
+ }
+
+ void setWriteMethod(Class> beanClass, String setterName)
+ throws IntrospectionException {
+ Method writeMethod = null;
+ try {
+ if (getter != null) {
+ writeMethod = beanClass.getMethod(setterName,
+ new Class[] { getter.getReturnType() });
+ } else {
+ Class> clazz = beanClass;
+ Method[] methods = null;
+ while (clazz != null && writeMethod == null) {
+ methods = clazz.getDeclaredMethods();
+ for (Method method : methods) {
+ if (setterName.equals(method.getName())) {
+ if (method.getParameterTypes().length == 1) {
+ writeMethod = method;
+ break;
+ }
+ }
+ }
+ clazz = clazz.getSuperclass();
+ }
+ }
+ } catch (Exception e) {
+ throw new IntrospectionException(e.getLocalizedMessage());
+ }
+ if (writeMethod == null) {
+ throw new IntrospectionException(Messages.getString(
+ "custom.beans.64", setterName)); //$NON-NLS-1$
+ }
+ setWriteMethod(writeMethod);
+ }
+
+ public PropertyEditor createPropertyEditor(Object bean) {
+ PropertyEditor editor;
+ if (propertyEditorClass == null) {
+ return null;
+ }
+ if (!PropertyEditor.class.isAssignableFrom(propertyEditorClass)) {
+ // custom.beans.48=Property editor is not assignable from the
+ // PropertyEditor interface
+ throw new ClassCastException(Messages.getString("custom.beans.48")); //$NON-NLS-1$
+ }
+ try {
+ Constructor> constr;
+ try {
+ // try to look for the constructor with single Object argument
+ constr = propertyEditorClass.getConstructor(Object.class);
+ editor = (PropertyEditor) constr.newInstance(bean);
+ } catch (NoSuchMethodException e) {
+ // try no-argument constructor
+ constr = propertyEditorClass.getConstructor();
+ editor = (PropertyEditor) constr.newInstance();
+ }
+ } catch (Exception e) {
+ // custom.beans.47=Unable to instantiate property editor
+ RuntimeException re = new RuntimeException(Messages
+ .getString("custom.beans.47"), e); //$NON-NLS-1$
+ throw re;
+ }
+ return editor;
+ }
+}
diff --git a/src/main/java/custom/beans/PropertyEditor.java b/src/main/java/custom/beans/PropertyEditor.java
new file mode 100644
index 000000000..4814f33f2
--- /dev/null
+++ b/src/main/java/custom/beans/PropertyEditor.java
@@ -0,0 +1,43 @@
+/* MODIFIED FOR THE MSGPACK PROJECT
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package custom.beans;
+
+import custom.beans.PropertyChangeListener;
+
+public interface PropertyEditor {
+
+ public void setAsText(String text) throws IllegalArgumentException;
+
+ public String[] getTags();
+
+ public String getJavaInitializationString();
+
+ public String getAsText();
+
+ public void setValue(Object value);
+
+ public Object getValue();
+
+ public void removePropertyChangeListener(PropertyChangeListener listener);
+
+ public void addPropertyChangeListener(PropertyChangeListener listener);
+
+ public boolean supportsCustomEditor();
+
+ public boolean isPaintable();
+}
diff --git a/src/main/java/custom/beans/PropertyVetoException.java b/src/main/java/custom/beans/PropertyVetoException.java
new file mode 100644
index 000000000..8fb5162ca
--- /dev/null
+++ b/src/main/java/custom/beans/PropertyVetoException.java
@@ -0,0 +1,55 @@
+/* MODIFIED FOR THE MSGPACK PROJECT
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package custom.beans;
+
+
+/**
+ * Indicates that a proposed property change is unacceptable.
+ */
+public class PropertyVetoException extends Exception {
+
+ private static final long serialVersionUID = 129596057694162164L;
+
+ private final PropertyChangeEvent evt;
+
+ /**
+ *
+ * Constructs an instance with a message and the change event.
+ *
+ *
+ * @param message
+ * A description of the veto.
+ * @param event
+ * The event that was vetoed.
+ */
+ public PropertyVetoException(String message, PropertyChangeEvent event) {
+ super(message);
+ this.evt = event;
+ }
+
+ /**
+ *
+ * Gets the property change event.
+ *
+ *
+ * @return An instance of {@link PropertyChangeEvent}
+ */
+ public PropertyChangeEvent getPropertyChangeEvent() {
+ return evt;
+ }
+}
diff --git a/src/main/java/custom/beans/SimpleBeanInfo.java b/src/main/java/custom/beans/SimpleBeanInfo.java
new file mode 100644
index 000000000..8c2e19ba9
--- /dev/null
+++ b/src/main/java/custom/beans/SimpleBeanInfo.java
@@ -0,0 +1,54 @@
+/* MODIFIED FOR THE MSGPACK PROJECT
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package custom.beans;
+
+
+public class SimpleBeanInfo implements BeanInfo {
+
+ public SimpleBeanInfo() {
+ // expected
+ }
+
+ public PropertyDescriptor[] getPropertyDescriptors() {
+ return null;
+ }
+
+ public MethodDescriptor[] getMethodDescriptors() {
+ return null;
+ }
+
+ public EventSetDescriptor[] getEventSetDescriptors() {
+ return null;
+ }
+
+ public BeanInfo[] getAdditionalBeanInfo() {
+ return null;
+ }
+
+ public BeanDescriptor getBeanDescriptor() {
+ return null;
+ }
+
+ public int getDefaultPropertyIndex() {
+ return -1;
+ }
+
+ public int getDefaultEventIndex() {
+ return -1;
+ }
+}
diff --git a/src/main/java/custom/beans/StandardBeanInfo.java b/src/main/java/custom/beans/StandardBeanInfo.java
new file mode 100644
index 000000000..192b59e8c
--- /dev/null
+++ b/src/main/java/custom/beans/StandardBeanInfo.java
@@ -0,0 +1,1505 @@
+/* MODIFIED FOR THE MSGPACK PROJECT
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package custom.beans;
+
+import static custom.beans.Introspector.decapitalize;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.EventListener;
+import java.util.EventObject;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TooManyListenersException;
+
+class StandardBeanInfo extends SimpleBeanInfo {
+
+ // Prefixes for methods that set or get a Property
+ private static final String PREFIX_IS = "is"; //$NON-NLS-1$
+
+ private static final String PREFIX_GET = "get"; //$NON-NLS-1$
+
+ private static final String PREFIX_SET = "set"; //$NON-NLS-1$
+
+ // Prefix and suffix for Event related methods
+ private static final String PREFIX_ADD = "add"; //$NON-NLS-1$
+
+ private static final String PREFIX_REMOVE = "remove"; //$NON-NLS-1$
+
+ private static final String SUFFIX_LISTEN = "Listener"; //$NON-NLS-1$
+
+ private static final String STR_NORMAL = "normal"; //$NON-NLS-1$
+
+ private static final String STR_INDEXED = "indexed"; //$NON-NLS-1$
+
+ private static final String STR_VALID = "valid"; //$NON-NLS-1$
+
+ private static final String STR_INVALID = "invalid"; //$NON-NLS-1$
+
+ private static final String STR_PROPERTY_TYPE = "PropertyType"; //$NON-NLS-1$
+
+ private static final String STR_IS_CONSTRAINED = "isConstrained"; //$NON-NLS-1$
+
+ private static final String STR_SETTERS = "setters"; //$NON-NLS-1$
+
+ private static final String STR_GETTERS = "getters"; //$NON-NLS-1$
+
+ private boolean explicitMethods = false;
+
+ private boolean explicitProperties = false;
+
+ private boolean explicitEvents = false;
+
+ private BeanInfo explicitBeanInfo = null;
+
+ private EventSetDescriptor[] events = null;
+
+ private MethodDescriptor[] methods = null;
+
+ private PropertyDescriptor[] properties = null;
+
+ private BeanDescriptor beanDescriptor = null;
+
+ BeanInfo[] additionalBeanInfo = null;
+
+ private Class> beanClass;
+
+ private int defaultEventIndex = -1;
+
+ private int defaultPropertyIndex = -1;
+
+ private static PropertyComparator comparator = new PropertyComparator();
+
+ private boolean canAddPropertyChangeListener;
+
+ private boolean canRemovePropertyChangeListener;
+
+ StandardBeanInfo(Class> beanClass, BeanInfo explicitBeanInfo, Class> stopClass)
+ throws IntrospectionException {
+ this.beanClass = beanClass;
+ /*--------------------------------------------------------------------------------------
+ * There are 3 aspects of BeanInfo that must be supplied:
+ * a) PropertyDescriptors
+ * b) MethodDescriptors
+ * c) EventSetDescriptors
+ * Each of these may be optionally provided in the explicitBeanInfo object relating to
+ * this bean. Where the explicitBeanInfo provides one of these aspects, it is used
+ * without question and no introspection of the beanClass is performed for that aspect.
+ * There are also 3 optional items of BeanInfo that may be provided by the
+ * explicitBeanInfo object:
+ * 1) BeanDescriptor
+ * 2) DefaultEventIndex
+ * 3) DefaultPropertyIndex
+ * These aspects of the beanClass cannot be derived through introspection of the class.
+ * If they are not provided by the explicitBeanInfo, then they must be left null in the
+ * returned BeanInfo, otherwise they will be copied from the explicitBeanInfo
+ --------------------------------------------------------------------------------------*/
+ if (explicitBeanInfo != null) {
+ this.explicitBeanInfo = explicitBeanInfo;
+ events = explicitBeanInfo.getEventSetDescriptors();
+ methods = explicitBeanInfo.getMethodDescriptors();
+ properties = explicitBeanInfo.getPropertyDescriptors();
+ defaultEventIndex = explicitBeanInfo.getDefaultEventIndex();
+ if (defaultEventIndex < 0 || defaultEventIndex >= events.length) {
+ defaultEventIndex = -1;
+ }
+ defaultPropertyIndex = explicitBeanInfo.getDefaultPropertyIndex();
+ if (defaultPropertyIndex < 0
+ || defaultPropertyIndex >= properties.length) {
+ defaultPropertyIndex = -1;
+ }
+ additionalBeanInfo = explicitBeanInfo.getAdditionalBeanInfo();
+
+ if (events != null)
+ explicitEvents = true;
+ if (methods != null)
+ explicitMethods = true;
+ if (properties != null)
+ explicitProperties = true;
+ }
+
+ if (methods == null) {
+ methods = introspectMethods();
+ }
+
+ if (properties == null) {
+ properties = introspectProperties(stopClass);
+ }
+
+ if (events == null) {
+ events = introspectEvents();
+ }
+ }
+
+ @Override
+ public BeanInfo[] getAdditionalBeanInfo() {
+ return null;
+ }
+
+ @Override
+ public EventSetDescriptor[] getEventSetDescriptors() {
+ return events;
+ }
+
+ @Override
+ public MethodDescriptor[] getMethodDescriptors() {
+ return methods;
+ }
+
+ @Override
+ public PropertyDescriptor[] getPropertyDescriptors() {
+ return properties;
+ }
+
+ @Override
+ public BeanDescriptor getBeanDescriptor() {
+ if (beanDescriptor == null) {
+ if (explicitBeanInfo != null) {
+ beanDescriptor = explicitBeanInfo.getBeanDescriptor();
+ }
+ if (beanDescriptor == null) {
+ beanDescriptor = new BeanDescriptor(beanClass);
+ }
+ }
+ return beanDescriptor;
+ }
+
+ @Override
+ public int getDefaultEventIndex() {
+ return this.defaultEventIndex;
+ }
+
+ @Override
+ public int getDefaultPropertyIndex() {
+ return this.defaultPropertyIndex;
+ }
+
+ void mergeBeanInfo(BeanInfo beanInfo, boolean force)
+ throws IntrospectionException {
+ if (force || !explicitProperties) {
+ PropertyDescriptor[] superDescs = beanInfo.getPropertyDescriptors();
+ if (superDescs != null) {
+ if (getPropertyDescriptors() != null) {
+ properties = mergeProps(superDescs, beanInfo
+ .getDefaultPropertyIndex());
+ } else {
+ properties = superDescs;
+ defaultPropertyIndex = beanInfo.getDefaultPropertyIndex();
+ }
+ }
+ }
+
+ if (force || !explicitMethods) {
+ MethodDescriptor[] superMethods = beanInfo.getMethodDescriptors();
+ if (superMethods != null) {
+ if (methods != null) {
+ methods = mergeMethods(superMethods);
+ } else {
+ methods = superMethods;
+ }
+ }
+ }
+
+ if (force || !explicitEvents) {
+ EventSetDescriptor[] superEvents = beanInfo
+ .getEventSetDescriptors();
+ if (superEvents != null) {
+ if (events != null) {
+ events = mergeEvents(superEvents, beanInfo
+ .getDefaultEventIndex());
+ } else {
+ events = superEvents;
+ defaultEventIndex = beanInfo.getDefaultEventIndex();
+ }
+ }
+ }
+ }
+
+ /* MODIFIED FOR THE MSGPACK PROJECT
+ * merge the PropertyDescriptor with superclass
+ */
+ private PropertyDescriptor[] mergeProps(PropertyDescriptor[] superDescs,
+ int superDefaultIndex) throws IntrospectionException {
+ // FIXME:change to OO way as EventSetD and MethodD
+ HashMap subMap = internalAsMap(properties);
+ String defaultPropertyName = null;
+ if (defaultPropertyIndex >= 0
+ && defaultPropertyIndex < properties.length) {
+ defaultPropertyName = properties[defaultPropertyIndex].getName();
+ } else if (superDefaultIndex >= 0
+ && superDefaultIndex < superDescs.length) {
+ defaultPropertyName = superDescs[superDefaultIndex].getName();
+ }
+
+ for (int i = 0; i < superDescs.length; i++) {
+ PropertyDescriptor superDesc = superDescs[i];
+ String propertyName = superDesc.getName();
+ if (!subMap.containsKey(propertyName)) {
+ subMap.put(propertyName, superDesc);
+ continue;
+ }
+
+ Object value = subMap.get(propertyName);
+ // if sub and super are both PropertyDescriptor
+ Method subGet = ((PropertyDescriptor) value).getReadMethod();
+ Method subSet = ((PropertyDescriptor) value).getWriteMethod();
+ Method superGet = superDesc.getReadMethod();
+ Method superSet = superDesc.getWriteMethod();
+
+ Class> superType = superDesc.getPropertyType();
+ Class> superIndexedType = null;
+ Class> subType = ((PropertyDescriptor) value).getPropertyType();
+ Class> subIndexedType = null;
+
+ if (value instanceof IndexedPropertyDescriptor) {
+ subIndexedType = ((IndexedPropertyDescriptor) value)
+ .getIndexedPropertyType();
+ }
+ if (superDesc instanceof IndexedPropertyDescriptor) {
+ superIndexedType = ((IndexedPropertyDescriptor) superDesc)
+ .getIndexedPropertyType();
+ }
+
+ // if superDesc is PropertyDescriptor
+ if (superIndexedType == null) {
+ PropertyDescriptor subDesc = (PropertyDescriptor) value;
+ // Sub is PropertyDescriptor
+ if (subIndexedType == null) {
+ // Same property type
+ if (subType != null && superType != null
+ && subType.getName() != null
+ && subType.getName().equals(superType.getName())) {
+ if (superGet != null
+ && (subGet == null || superGet.equals(subGet))) {
+ subDesc.setReadMethod(superGet);
+ }
+ if (superSet != null
+ && (subSet == null || superSet.equals(subSet))) {
+ subDesc.setWriteMethod(superSet);
+ }
+ if (subType == boolean.class && subGet != null
+ && superGet != null) {
+ if (superGet.getName().startsWith(PREFIX_IS)) {
+ subDesc.setReadMethod(superGet);
+ }
+ }
+ } else { // Different type
+ if ((subGet == null || subSet == null)
+ && (superGet != null)) {
+ subDesc = new PropertyDescriptor(propertyName,
+ superGet, superSet);
+ if (subGet != null) {
+ String subGetName = subGet.getName();
+ Method method = null;
+ MethodDescriptor[] introspectMethods = introspectMethods();
+ for (MethodDescriptor methodDesc : introspectMethods) {
+ method = methodDesc.getMethod();
+ if (method != subGet
+ && subGetName.equals(method
+ .getName())
+ && method.getParameterTypes().length == 0
+ && method.getReturnType() == superType) {
+ subDesc.setReadMethod(method);
+ break;
+ }
+ }
+ }
+ }
+ }
+ } else { // Sub is IndexedPropertyDescriptor and super is PropertyDescriptor
+ if (superType != null
+ && (superType.isArray())
+ && (superType.getComponentType().getName()
+ .equals(subIndexedType.getName()))) {
+ if ((subGet == null) && (superGet != null)) {
+ subDesc.setReadMethod(superGet);
+ }
+ if ((subSet == null) && (superSet != null)) {
+ subDesc.setWriteMethod(superSet);
+ }
+ } // different type do nothing
+ // sub is indexed pd and super is normal pd
+ if (subIndexedType == boolean.class
+ && superType == boolean.class) {
+ Method subIndexedSet = ((IndexedPropertyDescriptor) subDesc)
+ .getIndexedWriteMethod();
+ if (subGet == null && subSet == null
+ && subIndexedSet != null && superGet != null) {
+ try {
+ subSet = beanClass.getDeclaredMethod(
+ subIndexedSet.getName(), boolean.class);
+ } catch (Exception e) {
+ // ignored
+ }
+ if (subSet != null) {
+ // Cast sub into PropertyDescriptor
+ subDesc = new PropertyDescriptor(propertyName,
+ superGet, subSet);
+ }
+ }
+ }
+ }
+ subMap.put(propertyName, subDesc);
+ } else { // Super is IndexedPropertyDescriptor
+ if (subIndexedType == null) { // Sub is PropertyDescriptor
+ if (subType != null
+ && subType.isArray()
+ && (subType.getComponentType().getName()
+ .equals(superIndexedType.getName()))) {
+ // Same type
+ if (subGet != null) {
+ superDesc.setReadMethod(subGet);
+ }
+ if (subSet != null) {
+ superDesc.setWriteMethod(subSet);
+ }
+ subMap.put(propertyName, superDesc);
+ } else {
+ // subDesc is PropertyDescriptor
+ // superDesc is IndexedPropertyDescriptor
+
+ // fill null subGet or subSet method with superClass's
+ if (subGet == null || subSet == null) {
+ Class> beanSuperClass = beanClass.getSuperclass();
+ String methodSuffix = capitalize(propertyName);
+ Method method = null;
+ if (subGet == null) {
+ // subGet is null
+ if (subType == boolean.class) {
+ try {
+ method = beanSuperClass
+ .getDeclaredMethod(PREFIX_IS
+ + methodSuffix);
+ } catch (Exception e) {
+ // ignored
+ }
+ } else {
+ try {
+ method = beanSuperClass
+ .getDeclaredMethod(PREFIX_GET
+ + methodSuffix);
+ } catch (Exception e) {
+ // ignored
+ }
+ }
+ if (method != null
+ && !Modifier.isStatic(method
+ .getModifiers())
+ && method.getReturnType() == subType) {
+ ((PropertyDescriptor) value)
+ .setReadMethod(method);
+ }
+ } else {
+ // subSet is null
+ try {
+ method = beanSuperClass.getDeclaredMethod(
+ PREFIX_SET + methodSuffix, subType);
+ } catch (Exception e) {
+ // ignored
+ }
+ if (method != null
+ && !Modifier.isStatic(method
+ .getModifiers())
+ && method.getReturnType() == void.class) {
+ ((PropertyDescriptor) value)
+ .setWriteMethod(method);
+ }
+ }
+ }
+ subMap.put(propertyName, (PropertyDescriptor) value);
+ }
+ } else if (subIndexedType.getName().equals(
+ superIndexedType.getName())) {
+ // Sub is IndexedPropertyDescriptor and Same type
+ IndexedPropertyDescriptor subDesc = (IndexedPropertyDescriptor) value;
+ if ((subGet == null) && (superGet != null)) {
+ subDesc.setReadMethod(superGet);
+ }
+ if ((subSet == null) && (superSet != null)) {
+ subDesc.setWriteMethod(superSet);
+ }
+ IndexedPropertyDescriptor superIndexedDesc = (IndexedPropertyDescriptor) superDesc;
+
+ if ((subDesc.getIndexedReadMethod() == null)
+ && (superIndexedDesc.getIndexedReadMethod() != null)) {
+ subDesc.setIndexedReadMethod(superIndexedDesc
+ .getIndexedReadMethod());
+ }
+
+ if ((subDesc.getIndexedWriteMethod() == null)
+ && (superIndexedDesc.getIndexedWriteMethod() != null)) {
+ subDesc.setIndexedWriteMethod(superIndexedDesc
+ .getIndexedWriteMethod());
+ }
+
+ subMap.put(propertyName, subDesc);
+ } // Different indexed type, do nothing
+ }
+ mergeAttributes((PropertyDescriptor) value, superDesc);
+ }
+
+ PropertyDescriptor[] theDescs = new PropertyDescriptor[subMap.size()];
+ subMap.values().toArray(theDescs);
+
+ if (defaultPropertyName != null && !explicitProperties) {
+ for (int i = 0; i < theDescs.length; i++) {
+ if (defaultPropertyName.equals(theDescs[i].getName())) {
+ defaultPropertyIndex = i;
+ break;
+ }
+ }
+ }
+ return theDescs;
+ }
+
+ private String capitalize(String name) {
+ if (name == null) {
+ return null;
+ }
+ // The rule for decapitalize is that:
+ // If the first letter of the string is Upper Case, make it lower case
+ // UNLESS the second letter of the string is also Upper Case, in which case no
+ // changes are made.
+ if (name.length() == 0 || (name.length() > 1 && Character.isUpperCase(name.charAt(1)))) {
+ return name;
+ }
+
+ char[] chars = name.toCharArray();
+ chars[0] = Character.toUpperCase(chars[0]);
+ return new String(chars);
+ }
+
+ private static void mergeAttributes(PropertyDescriptor subDesc,
+ PropertyDescriptor superDesc) {
+ // FIXME: this is just temp workaround, need more elegant solution to
+ // handle this
+ subDesc.hidden |= superDesc.hidden;
+ subDesc.expert |= superDesc.expert;
+ subDesc.preferred |= superDesc.preferred;
+ subDesc.bound |= superDesc.bound;
+ subDesc.constrained |= superDesc.constrained;
+ subDesc.name = superDesc.name;
+ if (subDesc.shortDescription == null
+ && superDesc.shortDescription != null) {
+ subDesc.shortDescription = superDesc.shortDescription;
+ }
+ if (subDesc.displayName == null && superDesc.displayName != null) {
+ subDesc.displayName = superDesc.displayName;
+ }
+ }
+
+ /* MODIFIED FOR THE MSGPACK PROJECT
+ * merge the MethodDescriptor
+ */
+ private MethodDescriptor[] mergeMethods(MethodDescriptor[] superDescs) {
+ HashMap subMap = internalAsMap(methods);
+
+ for (MethodDescriptor superMethod : superDescs) {
+ String methodName = getQualifiedName(superMethod.getMethod());
+ MethodDescriptor method = subMap.get(methodName);
+ if (method == null) {
+ subMap.put(methodName, superMethod);
+ } else {
+ method.merge(superMethod);
+ }
+ }
+ MethodDescriptor[] theMethods = new MethodDescriptor[subMap.size()];
+ subMap.values().toArray(theMethods);
+ return theMethods;
+ }
+
+ private EventSetDescriptor[] mergeEvents(EventSetDescriptor[] otherEvents,
+ int otherDefaultIndex) {
+ HashMap subMap = internalAsMap(events);
+ String defaultEventName = null;
+ if (defaultEventIndex >= 0 && defaultEventIndex < events.length) {
+ defaultEventName = events[defaultEventIndex].getName();
+ } else if (otherDefaultIndex >= 0
+ && otherDefaultIndex < otherEvents.length) {
+ defaultEventName = otherEvents[otherDefaultIndex].getName();
+ }
+
+ for (EventSetDescriptor event : otherEvents) {
+ String eventName = event.getName();
+ EventSetDescriptor subEvent = subMap.get(eventName);
+ if (subEvent == null) {
+ subMap.put(eventName, event);
+ } else {
+ subEvent.merge(event);
+ }
+ }
+
+ EventSetDescriptor[] theEvents = new EventSetDescriptor[subMap.size()];
+ subMap.values().toArray(theEvents);
+
+ if (defaultEventName != null && !explicitEvents) {
+ for (int i = 0; i < theEvents.length; i++) {
+ if (defaultEventName.equals(theEvents[i].getName())) {
+ defaultEventIndex = i;
+ break;
+ }
+ }
+ }
+ return theEvents;
+ }
+
+ private static HashMap internalAsMap(
+ PropertyDescriptor[] propertyDescs) {
+ HashMap map = new HashMap();
+ for (int i = 0; i < propertyDescs.length; i++) {
+ map.put(propertyDescs[i].getName(), propertyDescs[i]);
+ }
+ return map;
+ }
+
+ private static HashMap internalAsMap(
+ MethodDescriptor[] theDescs) {
+ HashMap map = new HashMap();
+ for (int i = 0; i < theDescs.length; i++) {
+ String qualifiedName = getQualifiedName(theDescs[i].getMethod());
+ map.put(qualifiedName, theDescs[i]);
+ }
+ return map;
+ }
+
+ private static HashMap internalAsMap(
+ EventSetDescriptor[] theDescs) {
+ HashMap map = new HashMap();
+ for (int i = 0; i < theDescs.length; i++) {
+ map.put(theDescs[i].getName(), theDescs[i]);
+ }
+ return map;
+ }
+
+ private static String getQualifiedName(Method method) {
+ String qualifiedName = method.getName();
+ Class>[] paramTypes = method.getParameterTypes();
+ if (paramTypes != null) {
+ for (int i = 0; i < paramTypes.length; i++) {
+ qualifiedName += "_" + paramTypes[i].getName(); //$NON-NLS-1$
+ }
+ }
+ return qualifiedName;
+ }
+
+ /**
+ * Introspects the supplied class and returns a list of the public methods
+ * of the class
+ *
+ * @return An array of MethodDescriptors with the public methods. null if
+ * there are no public methods
+ */
+ private MethodDescriptor[] introspectMethods() {
+ return introspectMethods(false, beanClass);
+ }
+
+ private MethodDescriptor[] introspectMethods(boolean includeSuper) {
+ return introspectMethods(includeSuper, beanClass);
+ }
+
+ private MethodDescriptor[] introspectMethods(boolean includeSuper,
+ Class> introspectorClass) {
+
+ // Get the list of methods belonging to this class
+ Method[] basicMethods = includeSuper ? introspectorClass.getMethods()
+ : introspectorClass.getDeclaredMethods();
+
+ if (basicMethods == null || basicMethods.length == 0)
+ return null;
+
+ ArrayList methodList = new ArrayList(
+ basicMethods.length);
+
+ // Loop over the methods found, looking for public non-static methods
+ for (int i = 0; i < basicMethods.length; i++) {
+ int modifiers = basicMethods[i].getModifiers();
+ if (Modifier.isPublic(modifiers)) {
+ // Allocate a MethodDescriptor for this method
+ MethodDescriptor theDescriptor = new MethodDescriptor(
+ basicMethods[i]);
+ methodList.add(theDescriptor);
+ }
+ }
+
+ // Get the list of public methods into the returned array
+ int methodCount = methodList.size();
+ MethodDescriptor[] theMethods = null;
+ if (methodCount > 0) {
+ theMethods = new MethodDescriptor[methodCount];
+ theMethods = methodList.toArray(theMethods);
+ }
+
+ return theMethods;
+ }
+
+ /**
+ * Introspects the supplied class and returns a list of the Properties of
+ * the class
+ *
+ * @param stopClass -
+ * the to introspecting at
+ * @return The list of Properties as an array of PropertyDescriptors
+ * @throws IntrospectionException
+ */
+ @SuppressWarnings("rawtypes")
+ private PropertyDescriptor[] introspectProperties(Class> stopClass)
+ throws IntrospectionException {
+
+ // Get descriptors for the public methods
+ MethodDescriptor[] methodDescriptors = introspectMethods();
+
+ if (methodDescriptors == null) {
+ return null;
+ }
+
+ ArrayList methodList = new ArrayList();
+ // Loop over the methods found, looking for public non-static methods
+ for (int index = 0; index < methodDescriptors.length; index++) {
+ int modifiers = methodDescriptors[index].getMethod().getModifiers();
+ if (!Modifier.isStatic(modifiers)) {
+ methodList.add(methodDescriptors[index]);
+ }
+ }
+
+ // Get the list of public non-static methods into an array
+ int methodCount = methodList.size();
+ MethodDescriptor[] theMethods = null;
+ if (methodCount > 0) {
+ theMethods = new MethodDescriptor[methodCount];
+ theMethods = methodList.toArray(theMethods);
+ }
+
+ if (theMethods == null) {
+ return null;
+ }
+
+ HashMap propertyTable = new HashMap(
+ theMethods.length);
+
+ // Search for methods that either get or set a Property
+ for (int i = 0; i < theMethods.length; i++) {
+ introspectGet(theMethods[i].getMethod(), propertyTable);
+ introspectSet(theMethods[i].getMethod(), propertyTable);
+ }
+
+ // fix possible getter & setter collisions
+ fixGetSet(propertyTable);
+
+ // If there are listener methods, should be bound.
+ MethodDescriptor[] allMethods = introspectMethods(true);
+ if (stopClass != null) {
+ MethodDescriptor[] excludeMethods = introspectMethods(true,
+ stopClass);
+ if (excludeMethods != null) {
+ ArrayList tempMethods = new ArrayList();
+ for (MethodDescriptor method : allMethods) {
+ if (!isInSuper(method, excludeMethods)) {
+ tempMethods.add(method);
+ }
+ }
+ allMethods = tempMethods
+ .toArray(new MethodDescriptor[0]);
+ }
+ }
+ for (int i = 0; i < allMethods.length; i++) {
+ introspectPropertyListener(allMethods[i].getMethod());
+ }
+ // Put the properties found into the PropertyDescriptor array
+ ArrayList propertyList = new ArrayList();
+
+ for (Map.Entry entry : propertyTable.entrySet()) {
+ String propertyName = entry.getKey();
+ HashMap table = entry.getValue();
+ if (table == null) {
+ continue;
+ }
+ String normalTag = (String) table.get(STR_NORMAL);
+ String indexedTag = (String) table.get(STR_INDEXED);
+
+ if ((normalTag == null) && (indexedTag == null)) {
+ continue;
+ }
+
+ Method get = (Method) table.get(STR_NORMAL + PREFIX_GET);
+ Method set = (Method) table.get(STR_NORMAL + PREFIX_SET);
+ Method indexedGet = (Method) table.get(STR_INDEXED + PREFIX_GET);
+ Method indexedSet = (Method) table.get(STR_INDEXED + PREFIX_SET);
+
+ PropertyDescriptor propertyDesc = null;
+ if (indexedTag == null) {
+ propertyDesc = new PropertyDescriptor(propertyName, get, set);
+ } else {
+ try {
+ propertyDesc = new IndexedPropertyDescriptor(propertyName,
+ get, set, indexedGet, indexedSet);
+ } catch (IntrospectionException e) {
+ // If the getter and the indexGetter is not compatible, try
+ // getter/setter is null;
+ propertyDesc = new IndexedPropertyDescriptor(propertyName,
+ null, null, indexedGet, indexedSet);
+ }
+ }
+ // RI set propretyDescriptor as bound. FIXME
+ // propertyDesc.setBound(true);
+ if (canAddPropertyChangeListener && canRemovePropertyChangeListener) {
+ propertyDesc.setBound(true);
+ } else {
+ propertyDesc.setBound(false);
+ }
+ if (table.get(STR_IS_CONSTRAINED) == Boolean.TRUE) { //$NON-NLS-1$
+ propertyDesc.setConstrained(true);
+ }
+ propertyList.add(propertyDesc);
+ }
+
+ PropertyDescriptor[] theProperties = new PropertyDescriptor[propertyList
+ .size()];
+ propertyList.toArray(theProperties);
+ return theProperties;
+ }
+
+ private boolean isInSuper(MethodDescriptor method,
+ MethodDescriptor[] excludeMethods) {
+ for (MethodDescriptor m : excludeMethods) {
+ if (method.getMethod().equals(m.getMethod())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @SuppressWarnings("nls")
+ private void introspectPropertyListener(Method theMethod) {
+ String methodName = theMethod.getName();
+ Class>[] param = theMethod.getParameterTypes();
+ if (param.length != 1) {
+ return;
+ }
+ if (methodName.equals("addPropertyChangeListener")
+ && param[0].equals(PropertyChangeListener.class))
+ canAddPropertyChangeListener = true;
+ if (methodName.equals("removePropertyChangeListener")
+ && param[0].equals(PropertyChangeListener.class))
+ canRemovePropertyChangeListener = true;
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private static void introspectGet(Method theMethod,
+ HashMap propertyTable) {
+
+ String methodName = theMethod.getName();
+ int prefixLength = 0;
+ String propertyName;
+ Class propertyType;
+ Class[] paramTypes;
+ HashMap table;
+ ArrayList getters;
+
+ if (methodName == null) {
+ return;
+ }
+
+ if (methodName.startsWith(PREFIX_GET)) {
+ prefixLength = PREFIX_GET.length();
+ }
+
+ if (methodName.startsWith(PREFIX_IS)) {
+ prefixLength = PREFIX_IS.length();
+ }
+
+ if (prefixLength == 0) {
+ return;
+ }
+
+ propertyName = decapitalize(methodName.substring(prefixLength));
+
+ // validate property name
+ if (!isValidProperty(propertyName)) {
+ return;
+ }
+
+ // validate return type
+ propertyType = theMethod.getReturnType();
+
+ if (propertyType == null || propertyType == void.class) {
+ return;
+ }
+
+ // isXXX return boolean
+ if (prefixLength == 2) {
+ if (!(propertyType == boolean.class)) {
+ return;
+ }
+ }
+
+ // validate parameter types
+ paramTypes = theMethod.getParameterTypes();
+ if (paramTypes.length > 1
+ || (paramTypes.length == 1 && paramTypes[0] != int.class)) {
+ return;
+ }
+
+ table = propertyTable.get(propertyName);
+ if (table == null) {
+ table = new HashMap();
+ propertyTable.put(propertyName, table);
+ }
+
+ getters = (ArrayList) table.get(STR_GETTERS);
+ if (getters == null) {
+ getters = new ArrayList();
+ table.put(STR_GETTERS, getters);
+ }
+
+ // add current method as a valid getter
+ getters.add(theMethod);
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private static void introspectSet(Method theMethod,
+ HashMap propertyTable) {
+
+ String methodName = theMethod.getName();
+ if (methodName == null) {
+ return;
+ }
+ String propertyName;
+ Class returnType;
+ Class[] paramTypes;
+
+ // setter method should never return type other than void
+ returnType = theMethod.getReturnType();
+ if (returnType != void.class) {
+ return;
+ }
+
+ if (methodName == null || !methodName.startsWith(PREFIX_SET)) {
+ return;
+ }
+
+ propertyName = decapitalize(methodName.substring(PREFIX_SET.length()));
+
+ // validate property name
+ if (!isValidProperty(propertyName)) {
+ return;
+ }
+
+ // It seems we do not need to validate return type
+
+ // validate param types
+ paramTypes = theMethod.getParameterTypes();
+
+ if (paramTypes.length == 0 || paramTypes.length > 2
+ || (paramTypes.length == 2 && paramTypes[0] != int.class)) {
+ return;
+ }
+
+ HashMap table = propertyTable.get(propertyName);
+ if (table == null) {
+ table = new HashMap();
+ propertyTable.put(propertyName, table);
+ }
+
+ ArrayList setters = (ArrayList) table.get(STR_SETTERS);
+ if (setters == null) {
+ setters = new ArrayList();
+ table.put(STR_SETTERS, setters);
+ }
+
+ // handle constrained
+ Class[] exceptions = theMethod.getExceptionTypes();
+ for (Class e : exceptions) {
+ if (e.equals(PropertyVetoException.class)) {
+ table.put(STR_IS_CONSTRAINED, Boolean.TRUE); //$NON-NLS-1$
+ }
+ }
+
+ // add new setter
+ setters.add(theMethod);
+ }
+
+ /**
+ * Checks and fixs all cases when several incompatible checkers / getters
+ * were specified for single property.
+ *
+ * @param propertyTable
+ * @throws IntrospectionException
+ */
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private void fixGetSet(HashMap propertyTable)
+ throws IntrospectionException {
+
+ if (propertyTable == null) {
+ return;
+ }
+
+ for (Map.Entry entry : propertyTable.entrySet()) {
+ HashMap table = entry.getValue();
+ ArrayList getters = (ArrayList) table
+ .get(STR_GETTERS);
+ ArrayList setters = (ArrayList) table
+ .get(STR_SETTERS);
+
+ Method normalGetter = null;
+ Method indexedGetter = null;
+ Method normalSetter = null;
+ Method indexedSetter = null;
+
+ Class> normalPropType = null;
+ Class> indexedPropType = null;
+
+ if (getters == null) {
+ getters = new ArrayList();
+ }
+
+ if (setters == null) {
+ setters = new ArrayList();
+ }
+
+ // retrieve getters
+ Class>[] paramTypes = null;
+ String methodName = null;
+ for (Method getter : getters) {
+ paramTypes = getter.getParameterTypes();
+ methodName = getter.getName();
+ // checks if it's a normal getter
+ if (paramTypes == null || paramTypes.length == 0) {
+ // normal getter found
+ if (normalGetter == null
+ || methodName.startsWith(PREFIX_IS)) {
+ normalGetter = getter;
+ }
+ }
+
+ // checks if it's an indexed getter
+ if (paramTypes != null && paramTypes.length == 1
+ && paramTypes[0] == int.class) {
+ // indexed getter found
+ if (indexedGetter == null
+ || methodName.startsWith(PREFIX_GET)
+ || (methodName.startsWith(PREFIX_IS) && !indexedGetter
+ .getName().startsWith(PREFIX_GET))) {
+ indexedGetter = getter;
+ }
+ }
+ }
+
+ // retrieve normal setter
+ if (normalGetter != null) {
+ // Now we will try to look for normal setter of the same type.
+ Class> propertyType = normalGetter.getReturnType();
+
+ for (Method setter : setters) {
+ if (setter.getParameterTypes().length == 1
+ && propertyType
+ .equals(setter.getParameterTypes()[0])) {
+ normalSetter = setter;
+ break;
+ }
+ }
+ } else {
+ // Normal getter wasn't defined. Let's look for the last
+ // defined setter
+
+ for (Method setter : setters) {
+ if (setter.getParameterTypes().length == 1) {
+ normalSetter = setter;
+ }
+ }
+ }
+
+ // retrieve indexed setter
+ if (indexedGetter != null) {
+ // Now we will try to look for indexed setter of the same type.
+ Class> propertyType = indexedGetter.getReturnType();
+
+ for (Method setter : setters) {
+ if (setter.getParameterTypes().length == 2
+ && setter.getParameterTypes()[0] == int.class
+ && propertyType
+ .equals(setter.getParameterTypes()[1])) {
+ indexedSetter = setter;
+ break;
+ }
+ }
+ } else {
+ // Indexed getter wasn't defined. Let's look for the last
+ // defined indexed setter
+
+ for (Method setter : setters) {
+ if (setter.getParameterTypes().length == 2
+ && setter.getParameterTypes()[0] == int.class) {
+ indexedSetter = setter;
+ }
+ }
+ }
+
+ // determine property type
+ if (normalGetter != null) {
+ normalPropType = normalGetter.getReturnType();
+ } else if (normalSetter != null) {
+ normalPropType = normalSetter.getParameterTypes()[0];
+ }
+
+ // determine indexed getter/setter type
+ if (indexedGetter != null) {
+ indexedPropType = indexedGetter.getReturnType();
+ } else if (indexedSetter != null) {
+ indexedPropType = indexedSetter.getParameterTypes()[1];
+ }
+
+ // convert array-typed normal getters to indexed getters
+ if (normalGetter != null && normalGetter.getReturnType().isArray()) {
+
+ }
+
+ // RULES
+ // These rules were created after performing extensive black-box
+ // testing of RI
+
+ // RULE1
+ // Both normal getter and setter of the same type were defined;
+ // no indexed getter/setter *PAIR* of the other type defined
+ if (normalGetter != null && normalSetter != null
+ && (indexedGetter == null || indexedSetter == null)) {
+ table.put(STR_NORMAL, STR_VALID);
+ table.put(STR_NORMAL + PREFIX_GET, normalGetter);
+ table.put(STR_NORMAL + PREFIX_SET, normalSetter);
+ table.put(STR_NORMAL + STR_PROPERTY_TYPE, normalPropType);
+ continue;
+ }
+
+ // RULE2
+ // normal getter and/or setter was defined; no indexed
+ // getters & setters defined
+ if ((normalGetter != null || normalSetter != null)
+ && indexedGetter == null && indexedSetter == null) {
+ table.put(STR_NORMAL, STR_VALID);
+ table.put(STR_NORMAL + PREFIX_GET, normalGetter);
+ table.put(STR_NORMAL + PREFIX_SET, normalSetter);
+ table.put(STR_NORMAL + STR_PROPERTY_TYPE, normalPropType);
+ continue;
+ }
+
+ // RULE3
+ // mix of normal / indexed getters and setters are defined. Types
+ // are compatible
+ if ((normalGetter != null || normalSetter != null)
+ && (indexedGetter != null || indexedSetter != null)) {
+ // (1)!A!B!C!D
+ if (normalGetter != null && normalSetter != null
+ && indexedGetter != null && indexedSetter != null) {
+ if (indexedGetter.getName().startsWith(PREFIX_GET)) {
+ table.put(STR_NORMAL, STR_VALID);
+ table.put(STR_NORMAL + PREFIX_GET, normalGetter);
+ table.put(STR_NORMAL + PREFIX_SET, normalSetter);
+ table.put(STR_NORMAL + STR_PROPERTY_TYPE,
+ normalPropType);
+
+ table.put(STR_INDEXED, STR_VALID);
+ table.put(STR_INDEXED + PREFIX_GET, indexedGetter);
+ table.put(STR_INDEXED + PREFIX_SET, indexedSetter);
+ table.put(STR_INDEXED + STR_PROPERTY_TYPE,
+ indexedPropType);
+ } else {
+ if (normalPropType != boolean.class
+ && normalGetter.getName().startsWith(PREFIX_IS)) {
+ table.put(STR_INDEXED, STR_VALID);
+ table.put(STR_INDEXED + PREFIX_SET, indexedSetter);
+ table.put(STR_INDEXED + STR_PROPERTY_TYPE,
+ indexedPropType);
+ } else {
+ table.put(STR_NORMAL, STR_VALID);
+ table.put(STR_NORMAL + PREFIX_GET, normalGetter);
+ table.put(STR_NORMAL + PREFIX_SET, normalSetter);
+ table.put(STR_NORMAL + STR_PROPERTY_TYPE,
+ normalPropType);
+ }
+ }
+ continue;
+ }
+
+ // (2)!AB!C!D
+ if (normalGetter != null && normalSetter == null
+ && indexedGetter != null && indexedSetter != null) {
+ table.put(STR_NORMAL, STR_VALID);
+ table.put(STR_NORMAL + PREFIX_GET, normalGetter);
+ table.put(STR_NORMAL + PREFIX_SET, normalSetter);
+ table.put(STR_NORMAL + STR_PROPERTY_TYPE, normalPropType);
+
+ table.put(STR_INDEXED, STR_VALID);
+ if (indexedGetter.getName().startsWith(PREFIX_GET)) {
+ table.put(STR_INDEXED + PREFIX_GET, indexedGetter);
+ }
+ table.put(STR_INDEXED + PREFIX_SET, indexedSetter);
+ table.put(STR_INDEXED + STR_PROPERTY_TYPE, indexedPropType);
+ continue;
+ }
+
+ // (3)A!B!C!D
+ if (normalGetter == null && normalSetter != null
+ && indexedGetter != null && indexedSetter != null) {
+ table.put(STR_INDEXED, STR_VALID);
+ if (indexedGetter.getName().startsWith(PREFIX_GET)) {
+ table.put(STR_INDEXED + PREFIX_GET, indexedGetter);
+ }
+ table.put(STR_INDEXED + PREFIX_SET, indexedSetter);
+ table.put(STR_INDEXED + STR_PROPERTY_TYPE, indexedPropType);
+ continue;
+ }
+
+ // (4)!AB!CD
+ if (normalGetter != null && normalSetter == null
+ && indexedGetter != null && indexedSetter == null) {
+ if (indexedGetter.getName().startsWith(PREFIX_GET)) {
+ table.put(STR_NORMAL, STR_VALID);
+ table.put(STR_NORMAL + PREFIX_GET, normalGetter);
+ table.put(STR_NORMAL + PREFIX_SET, normalSetter);
+ table.put(STR_NORMAL + STR_PROPERTY_TYPE,
+ normalPropType);
+
+ table.put(STR_INDEXED, STR_VALID);
+ table.put(STR_INDEXED + PREFIX_GET, indexedGetter);
+ table.put(STR_INDEXED + PREFIX_SET, indexedSetter);
+ table.put(STR_INDEXED + STR_PROPERTY_TYPE,
+ indexedPropType);
+ } else {
+ table.put(STR_NORMAL, STR_VALID);
+ table.put(STR_NORMAL + PREFIX_GET, normalGetter);
+ table.put(STR_NORMAL + PREFIX_SET, normalSetter);
+ table.put(STR_NORMAL + STR_PROPERTY_TYPE,
+ normalPropType);
+ }
+ continue;
+ }
+
+ // (5)A!B!CD
+ if (normalGetter == null && normalSetter != null
+ && indexedGetter != null && indexedSetter == null) {
+ if (indexedGetter.getName().startsWith(PREFIX_GET)) {
+ table.put(STR_NORMAL, STR_VALID);
+ table.put(STR_NORMAL + PREFIX_GET, normalGetter);
+ table.put(STR_NORMAL + PREFIX_SET, normalSetter);
+ table.put(STR_NORMAL + STR_PROPERTY_TYPE,
+ normalPropType);
+
+ table.put(STR_INDEXED, STR_VALID);
+ table.put(STR_INDEXED + PREFIX_GET, indexedGetter);
+ table.put(STR_INDEXED + PREFIX_SET, indexedSetter);
+ table.put(STR_INDEXED + STR_PROPERTY_TYPE,
+ indexedPropType);
+ } else {
+ table.put(STR_NORMAL, STR_VALID);
+ table.put(STR_NORMAL + PREFIX_GET, normalGetter);
+ table.put(STR_NORMAL + PREFIX_SET, normalSetter);
+ table.put(STR_NORMAL + STR_PROPERTY_TYPE,
+ normalPropType);
+ }
+ continue;
+ }
+
+ // (6)!ABC!D
+ if (normalGetter != null && normalSetter == null
+ && indexedGetter == null && indexedSetter != null) {
+ table.put(STR_INDEXED, STR_VALID);
+ table.put(STR_INDEXED + PREFIX_GET, indexedGetter);
+ table.put(STR_INDEXED + PREFIX_SET, indexedSetter);
+ table.put(STR_INDEXED + STR_PROPERTY_TYPE, indexedPropType);
+ continue;
+ }
+
+ // (7)A!BC!D
+ if (normalGetter == null && normalSetter != null
+ && indexedGetter == null && indexedSetter != null) {
+ table.put(STR_INDEXED, STR_VALID);
+ table.put(STR_INDEXED + PREFIX_GET, indexedGetter);
+ table.put(STR_INDEXED + PREFIX_SET, indexedSetter);
+ table.put(STR_INDEXED + STR_PROPERTY_TYPE, indexedPropType);
+ continue;
+ }
+ }
+
+ // RULE4
+ // no normal normal getter / setter.
+ // Only indexed getter and/or setter is given
+ // no normal setters / getters defined
+ if (normalSetter == null && normalGetter == null
+ && (indexedGetter != null || indexedSetter != null)) {
+ if (indexedGetter != null
+ && indexedGetter.getName().startsWith(PREFIX_IS)) {
+ if (indexedSetter != null) {
+ table.put(STR_INDEXED, STR_VALID);
+ table.put(STR_INDEXED + PREFIX_SET, indexedSetter);
+ table.put(STR_INDEXED + STR_PROPERTY_TYPE,
+ indexedPropType);
+ }
+ continue;
+ }
+ table.put(STR_INDEXED, STR_VALID);
+ table.put(STR_INDEXED + PREFIX_GET, indexedGetter);
+ table.put(STR_INDEXED + PREFIX_SET, indexedSetter);
+ table.put(STR_INDEXED + STR_PROPERTY_TYPE, indexedPropType);
+ continue;
+ }
+
+ // RULE5
+ // Both indexed getter and setter methods are defined
+ // no normal getter/setter *PAIR* of the other type defined
+ if ((normalSetter != null || normalGetter != null)
+ && indexedGetter != null && indexedSetter != null) {
+ table.put(STR_INDEXED, STR_VALID);
+ table.put(STR_INDEXED + PREFIX_GET, indexedGetter);
+ table.put(STR_INDEXED + PREFIX_SET, indexedSetter);
+ table.put(STR_INDEXED + STR_PROPERTY_TYPE, indexedPropType);
+ continue;
+ }
+
+ // default rule - invalid property
+ table.put(STR_NORMAL, STR_INVALID);
+ table.put(STR_INDEXED, STR_INVALID);
+ }
+
+ }
+
+ /**
+ * Introspects the supplied Bean class and returns a list of the Events of
+ * the class
+ *
+ * @return the events
+ * @throws IntrospectionException
+ */
+ @SuppressWarnings({ "rawtypes" })
+ private EventSetDescriptor[] introspectEvents() throws IntrospectionException {
+ // Get descriptors for the public methods
+ // FIXME: performance
+ MethodDescriptor[] theMethods = introspectMethods();
+
+ if (theMethods == null)
+ return null;
+
+ HashMap eventTable = new HashMap(
+ theMethods.length);
+
+ // Search for methods that add an Event Listener
+ for (int i = 0; i < theMethods.length; i++) {
+ introspectListenerMethods(PREFIX_ADD, theMethods[i].getMethod(),
+ eventTable);
+ introspectListenerMethods(PREFIX_REMOVE, theMethods[i].getMethod(),
+ eventTable);
+ introspectGetListenerMethods(theMethods[i].getMethod(), eventTable);
+ }
+
+ ArrayList eventList = new ArrayList();
+ for (Map.Entry entry : eventTable.entrySet()) {
+ HashMap table = entry.getValue();
+ Method add = (Method) table.get(PREFIX_ADD);
+ Method remove = (Method) table.get(PREFIX_REMOVE);
+
+ if ((add == null) || (remove == null)) {
+ continue;
+ }
+
+ Method get = (Method) table.get(PREFIX_GET);
+ Class> listenerType = (Class) table.get("listenerType"); //$NON-NLS-1$
+ Method[] listenerMethods = (Method[]) table.get("listenerMethods"); //$NON-NLS-1$
+ EventSetDescriptor eventSetDescriptor = new EventSetDescriptor(
+ decapitalize(entry.getKey()), listenerType, listenerMethods, add,
+ remove, get);
+
+ eventSetDescriptor.setUnicast(table.get("isUnicast") != null); //$NON-NLS-1$
+ eventList.add(eventSetDescriptor);
+ }
+
+ EventSetDescriptor[] theEvents = new EventSetDescriptor[eventList
+ .size()];
+ eventList.toArray(theEvents);
+
+ return theEvents;
+ }
+
+ /* MODIFIED FOR THE MSGPACK PROJECT
+ * find the add, remove listener method
+ */
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private static void introspectListenerMethods(String type,
+ Method theMethod, HashMap methodsTable) {
+ String methodName = theMethod.getName();
+ if (methodName == null) {
+ return;
+ }
+
+ if (!((methodName.startsWith(type)) && (methodName
+ .endsWith(SUFFIX_LISTEN)))) {
+ return;
+ }
+
+ String listenerName = methodName.substring(type.length());
+ String eventName = listenerName.substring(0, listenerName
+ .lastIndexOf(SUFFIX_LISTEN));
+ if ((eventName == null) || (eventName.length() == 0)) {
+ return;
+ }
+
+ Class[] paramTypes = theMethod.getParameterTypes();
+ if ((paramTypes == null) || (paramTypes.length != 1)) {
+ return;
+ }
+
+ Class> listenerType = paramTypes[0];
+
+ if (!EventListener.class.isAssignableFrom(listenerType)) {
+ return;
+ }
+
+ if (!listenerType.getName().endsWith(listenerName)) {
+ return;
+ }
+
+ HashMap table = methodsTable.get(eventName);
+ if (table == null) {
+ table = new HashMap();
+ }
+ // put listener type
+ if (table.get("listenerType") == null) { //$NON-NLS-1$
+ table.put("listenerType", listenerType); //$NON-NLS-1$
+ table.put("listenerMethods", //$NON-NLS-1$
+ introspectListenerMethods(listenerType));
+ }
+ // put add / remove
+ table.put(type, theMethod);
+
+ // determine isUnicast()
+ if (type.equals(PREFIX_ADD)) {
+ Class[] exceptionTypes = theMethod.getExceptionTypes();
+ if (exceptionTypes != null) {
+ for (int i = 0; i < exceptionTypes.length; i++) {
+ if (exceptionTypes[i].getName().equals(
+ TooManyListenersException.class.getName())) {
+ table.put("isUnicast", "true"); //$NON-NLS-1$//$NON-NLS-2$
+ break;
+ }
+ }
+ }
+ }
+
+ methodsTable.put(eventName, table);
+ }
+
+ private static Method[] introspectListenerMethods(Class> listenerType) {
+ Method[] methods = listenerType.getDeclaredMethods();
+ ArrayList list = new ArrayList();
+ for (int i = 0; i < methods.length; i++) {
+ Class>[] paramTypes = methods[i].getParameterTypes();
+ if (paramTypes.length != 1) {
+ continue;
+ }
+
+ if (EventObject.class.isAssignableFrom(paramTypes[0])) {
+ list.add(methods[i]);
+ }
+ }
+ Method[] matchedMethods = new Method[list.size()];
+ list.toArray(matchedMethods);
+ return matchedMethods;
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private static void introspectGetListenerMethods(Method theMethod,
+ HashMap methodsTable) {
+ String type = PREFIX_GET;
+
+ String methodName = theMethod.getName();
+ if (methodName == null) {
+ return;
+ }
+
+ if (!((methodName.startsWith(type)) && (methodName
+ .endsWith(SUFFIX_LISTEN + "s")))) { //$NON-NLS-1$
+ return;
+ }
+
+ String listenerName = methodName.substring(type.length(), methodName
+ .length() - 1);
+ String eventName = listenerName.substring(0, listenerName
+ .lastIndexOf(SUFFIX_LISTEN));
+ if ((eventName == null) || (eventName.length() == 0)) {
+ return;
+ }
+
+ Class[] paramTypes = theMethod.getParameterTypes();
+ if ((paramTypes == null) || (paramTypes.length != 0)) {
+ return;
+ }
+
+ Class returnType = theMethod.getReturnType();
+ if ((returnType.getComponentType() == null)
+ || (!returnType.getComponentType().getName().endsWith(
+ listenerName))) {
+ return;
+ }
+
+ HashMap table = methodsTable.get(eventName);
+ if (table == null) {
+ table = new HashMap();
+ }
+ // put add / remove
+ table.put(type, theMethod);
+ methodsTable.put(eventName, table);
+ }
+
+ private static boolean isValidProperty(String propertyName) {
+ return (propertyName != null) && (propertyName.length() != 0);
+ }
+
+ private static class PropertyComparator implements
+ Comparator {
+ public int compare(PropertyDescriptor object1,
+ PropertyDescriptor object2) {
+ return object1.getName().compareTo(object2.getName());
+ }
+
+ }
+
+ // TODO
+ void init() {
+ if (this.events == null) {
+ events = new EventSetDescriptor[0];
+ }
+ if (this.properties == null) {
+ this.properties = new PropertyDescriptor[0];
+ }
+
+ if (properties != null) {
+ String defaultPropertyName = (defaultPropertyIndex != -1 ? properties[defaultPropertyIndex]
+ .getName()
+ : null);
+ Arrays.sort(properties, comparator);
+ if (null != defaultPropertyName) {
+ for (int i = 0; i < properties.length; i++) {
+ if (defaultPropertyName.equals(properties[i].getName())) {
+ defaultPropertyIndex = i;
+ break;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/custom/beans/Statement.java b/src/main/java/custom/beans/Statement.java
new file mode 100644
index 000000000..5a8d5be33
--- /dev/null
+++ b/src/main/java/custom/beans/Statement.java
@@ -0,0 +1,610 @@
+/* MODIFIED FOR THE MSGPACK PROJECT
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package custom.beans;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.apache.harmony.beans.BeansUtils;
+import org.apache.harmony.beans.internal.nls.Messages;
+
+public class Statement {
+
+ private Object target;
+
+ private String methodName;
+
+ private Object[] arguments;
+
+ // cache used methods of specified target class to accelerate method search
+ private static WeakHashMap, Method[]> classMethodsCache = new WeakHashMap, Method[]>();
+
+ public Statement(Object target, String methodName, Object[] arguments) {
+ this.target = target;
+ this.methodName = methodName;
+ this.arguments = arguments == null ? BeansUtils.EMPTY_OBJECT_ARRAY
+ : arguments;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ if (target == null) {
+ sb.append(BeansUtils.NULL);
+ } else {
+ Class> clazz = target.getClass();
+ sb.append(clazz == String.class ? BeansUtils.QUOTE : BeansUtils
+ .idOfClass(clazz));
+ }
+ sb.append('.' + methodName + '(');
+ if (arguments != null) {
+ Class> clazz;
+ for (int index = 0; index < arguments.length; index++) {
+ if (index > 0) {
+ sb.append(", "); //$NON-NLS-1$
+ }
+ if (arguments[index] == null) {
+ sb.append(BeansUtils.NULL);
+ } else {
+ clazz = arguments[index].getClass();
+ sb.append(clazz == String.class ? '"' + (String) arguments[index] + '"'
+ : BeansUtils.idOfClass(clazz));
+ }
+ }
+ }
+ sb.append(')');
+ sb.append(';');
+ return sb.toString();
+ }
+
+ public String getMethodName() {
+ return methodName;
+ }
+
+ public Object[] getArguments() {
+ return arguments;
+ }
+
+ public Object getTarget() {
+ return target;
+ }
+
+ public void execute() throws Exception {
+ invokeMethod();
+ }
+
+ Object invokeMethod() throws Exception {
+ Object result = null;
+ try {
+ Object target = getTarget();
+ String methodName = getMethodName();
+ Object[] arguments = getArguments();
+ Class> targetClass = target.getClass();
+ if (targetClass.isArray()) {
+ Method method = findArrayMethod(methodName, arguments);
+ Object[] copy = new Object[arguments.length + 1];
+ copy[0] = target;
+ System.arraycopy(arguments, 0, copy, 1, arguments.length);
+ result = method.invoke(null, copy);
+ } else if (BeansUtils.NEWINSTANCE.equals(methodName)
+ && target == Array.class) {
+ result = Array.newInstance((Class>) arguments[0],
+ ((Integer) arguments[1]).intValue());
+ } else if (BeansUtils.NEW.equals(methodName)
+ || BeansUtils.NEWINSTANCE.equals(methodName)) {
+ if (target instanceof Class>) {
+ Constructor> constructor = findConstructor(
+ (Class>) target, arguments);
+ result = constructor.newInstance(arguments);
+ } else {
+ if (BeansUtils.NEW.equals(methodName)) {
+ throw new NoSuchMethodException(this.toString());
+ }
+ // target class declares a public named "newInstance" method
+ Method method = findMethod(targetClass, methodName,
+ arguments, false);
+ result = method.invoke(target, arguments);
+ }
+ } else if (methodName.equals(BeansUtils.NEWARRAY)) {
+ // create a new array instance without length attribute
+ Class> clazz = (Class>) target, argClass;
+
+ // check the element types of array
+ for (int index = 0; index < arguments.length; index++) {
+ argClass = arguments[index] == null ? null
+ : arguments[index].getClass();
+ if (argClass != null && !clazz.isAssignableFrom(argClass)
+ && !BeansUtils.isPrimitiveWrapper(argClass, clazz)) {
+ throw new IllegalArgumentException(
+ Messages.getString("custom.beans.63")); //$NON-NLS-1$
+ }
+ }
+ result = Array.newInstance(clazz, arguments.length);
+ if (clazz.isPrimitive()) {
+ // Copy element according to primitive types
+ arrayCopy(clazz, arguments, result, arguments.length);
+ } else {
+ // Copy element of Objects
+ System.arraycopy(arguments, 0, result, 0, arguments.length);
+ }
+ return result;
+ } else if (target instanceof Class>) {
+ Method method = null;
+ try {
+ /* MODIFIED FOR THE MSGPACK PROJECT
+ * Try to look for a static method of class described by the
+ * given Class object at first process only if the class
+ * differs from Class itself
+ */
+ if (target != Class.class) {
+ method = findMethod((Class>) target, methodName,
+ arguments, true);
+ result = method.invoke(null, arguments);
+ }
+ } catch (NoSuchMethodException e) {
+ // expected
+ }
+ if (method == null) {
+ // static method was not found
+ // try to invoke method of Class object
+ if (BeansUtils.FORNAME.equals(methodName)
+ && arguments.length == 1
+ && arguments[0] instanceof String) {
+ // special handling of Class.forName(String)
+ try {
+ result = Class.forName((String) arguments[0]);
+ } catch (ClassNotFoundException e2) {
+ result = Class.forName((String) arguments[0], true,
+ Thread.currentThread()
+ .getContextClassLoader());
+ }
+ } else {
+ method = findMethod(targetClass, methodName, arguments,
+ false);
+ result = method.invoke(target, arguments);
+ }
+ }
+ } else if (target instanceof Iterator>) {
+ final Iterator> iterator = (Iterator>) target;
+ final Method method = findMethod(targetClass, methodName,
+ arguments, false);
+ if (iterator.hasNext()) {
+ result = new PrivilegedAction