All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openmdx.dalvik.uses.java.beans.DefaultPersistenceDelegate Maven / Gradle / Ivy

There is a newer version: 2.18.10
Show newest version
/*
 * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package org.openmdx.dalvik.uses.java.beans;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.openmdx.dalvik.uses.sun.reflect.misc.MethodUtil;


/**
 * The DefaultPersistenceDelegate is a concrete implementation of
 * the abstract PersistenceDelegate class and
 * is the delegate used by default for classes about
 * which no information is available. The DefaultPersistenceDelegate
 * provides, version resilient, public API-based persistence for
 * classes that follow the JavaBeans conventions without any class specific
 * configuration.
 * 

* The key assumptions are that the class has a nullary constructor * and that its state is accurately represented by matching pairs * of "setter" and "getter" methods in the order they are returned * by the Introspector. * In addition to providing code-free persistence for JavaBeans, * the DefaultPersistenceDelegate provides a convenient means * to effect persistent storage for classes that have a constructor * that, while not nullary, simply requires some property values * as arguments. * * @see #DefaultPersistenceDelegate(String[]) * @see org.openmdx.dalvik.uses.java.beans.Introspector * *

* openMDX/Dalvik Notice (January 2013):
* THIS CODE HAS BEEN MODIFIED AND ITS NAMESPACE HAS BEEN PREFIXED WITH * org.openmdx.dalvik.uses. *

* @since openMDX 2.12 * @author openMDX Team * * @author Philip Milne */ @SuppressWarnings({"rawtypes","unchecked"}) public class DefaultPersistenceDelegate extends PersistenceDelegate { private String[] constructor; private Boolean definesEquals; /** * Creates a persistence delegate for a class with a nullary constructor. * * @see #DefaultPersistenceDelegate(java.lang.String[]) */ public DefaultPersistenceDelegate() { this(new String[0]); } /** * Creates a default persistence delegate for a class with a * constructor whose arguments are the values of the property * names as specified by constructorPropertyNames. * The constructor arguments are created by * evaluating the property names in the order they are supplied. * To use this class to specify a single preferred constructor for use * in the serialization of a particular type, we state the * names of the properties that make up the constructor's * arguments. For example, the Font class which * does not define a nullary constructor can be handled * with the following persistence delegate: * *
     *     new DefaultPersistenceDelegate(new String[]{"name", "style", "size"});
     * 
* * @param constructorPropertyNames The property names for the arguments of this constructor. * * @see #instantiate */ public DefaultPersistenceDelegate(String[] constructorPropertyNames) { this.constructor = constructorPropertyNames; } private static boolean definesEquals(Class type) { try { return type == type.getMethod("equals", Object.class).getDeclaringClass(); } catch(NoSuchMethodException e) { return false; } } private boolean definesEquals(Object instance) { if (definesEquals != null) { return (definesEquals == Boolean.TRUE); } else { boolean result = definesEquals(instance.getClass()); definesEquals = result ? Boolean.TRUE : Boolean.FALSE; return result; } } /** * If the number of arguments in the specified constructor is non-zero and * the class of oldInstance explicitly declares an "equals" method * this method returns the value of oldInstance.equals(newInstance). * Otherwise, this method uses the superclass's definition which returns true if the * classes of the two instances are equal. * * @param oldInstance The instance to be copied. * @param newInstance The instance that is to be modified. * @return True if an equivalent copy of newInstance may be * created by applying a series of mutations to oldInstance. * * @see #DefaultPersistenceDelegate(String[]) */ protected boolean mutatesTo(Object oldInstance, Object newInstance) { // Assume the instance is either mutable or a singleton // if it has a nullary constructor. return (constructor.length == 0) || !definesEquals(oldInstance) ? super.mutatesTo(oldInstance, newInstance) : oldInstance.equals(newInstance); } /** * This default implementation of the instantiate method returns * an expression containing the predefined method name "new" which denotes a * call to a constructor with the arguments as specified in * the DefaultPersistenceDelegate's constructor. * * @param oldInstance The instance to be instantiated. * @param out The code output stream. * @return An expression whose value is oldInstance. * * @see #DefaultPersistenceDelegate(String[]) */ protected Expression instantiate(Object oldInstance, Encoder out) { int nArgs = constructor.length; Class type = oldInstance.getClass(); Object[] constructorArgs = new Object[nArgs]; for(int i = 0; i < nArgs; i++) { try { Method method = findMethod(type, this.constructor[i]); constructorArgs[i] = MethodUtil.invoke(method, oldInstance, new Object[0]); } catch (Exception e) { out.getExceptionListener().exceptionThrown(e); } } return new Expression(oldInstance, oldInstance.getClass(), "new", constructorArgs); } private Method findMethod(Class type, String property) throws IntrospectionException { if (property == null) { throw new IllegalArgumentException("Property name is null"); } BeanInfo info = Introspector.getBeanInfo(type); for (PropertyDescriptor pd : info.getPropertyDescriptors()) { if (property.equals(pd.getName())) { Method method = pd.getReadMethod(); if (method != null) { return method; } throw new IllegalStateException("Could not find getter for the property " + property); } } throw new IllegalStateException("Could not find property by the name " + property); } // This is a workaround for a bug in the introspector. // PropertyDescriptors are not shared amongst subclasses. private boolean isTransient(Class type, PropertyDescriptor pd) { if (type == null) { return false; } // This code was mistakenly deleted - it may be fine and // is more efficient than the code below. This should // all disappear anyway when property descriptors are shared // by the introspector. /* Method getter = pd.getReadMethod(); Class declaringClass = getter.getDeclaringClass(); if (declaringClass == type) { return Boolean.TRUE.equals(pd.getValue("transient")); } */ String pName = pd.getName(); BeanInfo info = MetaData.getBeanInfo(type); PropertyDescriptor[] propertyDescriptors = info.getPropertyDescriptors(); for (int i = 0; i < propertyDescriptors.length; ++i ) { PropertyDescriptor pd2 = propertyDescriptors[i]; if (pName.equals(pd2.getName())) { Object value = pd2.getValue("transient"); if (value != null) { return Boolean.TRUE.equals(value); } } } return isTransient(type.getSuperclass(), pd); } private static boolean equals(Object o1, Object o2) { return (o1 == null) ? (o2 == null) : o1.equals(o2); } private void doProperty(Class type, PropertyDescriptor pd, Object oldInstance, Object newInstance, Encoder out) throws Exception { Method getter = pd.getReadMethod(); Method setter = pd.getWriteMethod(); if (getter != null && setter != null && !isTransient(type, pd)) { Expression oldGetExp = new Expression(oldInstance, getter.getName(), new Object[]{}); Expression newGetExp = new Expression(newInstance, getter.getName(), new Object[]{}); Object oldValue = oldGetExp.getValue(); Object newValue = newGetExp.getValue(); out.writeExpression(oldGetExp); if (!equals(newValue, out.get(oldValue))) { // Search for a static constant with this value; Object e = (Object[])pd.getValue("enumerationValues"); if (e instanceof Object[] && Array.getLength(e) % 3 == 0) { Object[] a = (Object[])e; for(int i = 0; i < a.length; i = i + 3) { try { Field f = type.getField((String)a[i]); if (f.get(null).equals(oldValue)) { out.remove(oldValue); out.writeExpression(new Expression(oldValue, f, "get", new Object[]{null})); } } catch (Exception ex) {} } } invokeStatement(oldInstance, setter.getName(), new Object[]{oldValue}, out); } } } static void invokeStatement(Object instance, String methodName, Object[] args, Encoder out) { out.writeStatement(new Statement(instance, methodName, args)); } // Write out the properties of this instance. private void initBean(Class type, Object oldInstance, Object newInstance, Encoder out) { // System.out.println("initBean: " + oldInstance); BeanInfo info = MetaData.getBeanInfo(type); // Properties PropertyDescriptor[] propertyDescriptors = info.getPropertyDescriptors(); for (int i = 0; i < propertyDescriptors.length; ++i ) { try { doProperty(type, propertyDescriptors[i], oldInstance, newInstance, out); } catch (Exception e) { out.getExceptionListener().exceptionThrown(e); } } // AWT handling removed } /** * This default implementation of the initialize method assumes * all state held in objects of this type is exposed via the * matching pairs of "setter" and "getter" methods in the order * they are returned by the Introspector. If a property descriptor * defines a "transient" attribute with a value equal to * Boolean.TRUE the property is ignored by this * default implementation. Note that this use of the word * "transient" is quite independent of the field modifier * that is used by the ObjectOutputStream. *

* For each non-transient property, an expression is created * in which the nullary "getter" method is applied * to the oldInstance. The value of this * expression is the value of the property in the instance that is * being serialized. If the value of this expression * in the cloned environment mutatesTo the * target value, the new value is initialized to make it * equivalent to the old value. In this case, because * the property value has not changed there is no need to * call the corresponding "setter" method and no statement * is emitted. If not however, the expression for this value * is replaced with another expression (normally a constructor) * and the corresponding "setter" method is called to install * the new property value in the object. This scheme removes * default information from the output produced by streams * using this delegate. *

* In passing these statements to the output stream, where they * will be executed, side effects are made to the newInstance. * In most cases this allows the problem of properties * whose values depend on each other to actually help the * serialization process by making the number of statements * that need to be written to the output smaller. In general, * the problem of handling interdependent properties is reduced to * that of finding an order for the properties in * a class such that no property value depends on the value of * a subsequent property. * * @param oldInstance The instance to be copied. * @param newInstance The instance that is to be modified. * @param out The stream to which any initialization statements should be written. * * @see org.openmdx.dalvik.uses.java.beans.Introspector#getBeanInfo * @see org.openmdx.dalvik.uses.java.beans.PropertyDescriptor */ protected void initialize(Class type, Object oldInstance, Object newInstance, Encoder out) { // System.out.println("DefulatPD:initialize" + type); super.initialize(type, oldInstance, newInstance, out); if (oldInstance.getClass() == type) { // !type.isInterface()) { initBean(type, oldInstance, newInstance, out); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy