Skip to content

Commit

Permalink
Merge change from /harmony/enhanced/java/trunk@1022963:
Browse files Browse the repository at this point in the history
  r1022963 | zhoukevin | 2010-10-15 16:17:01 +0100 (Fri, 15 Oct 2010) | 2 lines

  For objects of types generated by methods of java.util.Collections class,
  like java.util.Collections$UnmodifiableCollection generated by
  java.util.Collections.unmodifiableCollection(Collection) method etc,
  HARMONY has problem to encode and decode them while Oracle JDK doesn't.
  This patch also adds several test cases to reproduce those problems.


git-svn-id: https://svn.apache.org/repos/asf/harmony/enhanced/java/branches/java6@1027958 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
Mark Hindess committed Oct 27, 2010
1 parent 8d413f6 commit 5780971
Show file tree
Hide file tree
Showing 30 changed files with 2,162 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
/*
* 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 java.beans;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;

import org.apache.harmony.beans.BeansUtils;

public class UtilCollectionsPersistenceDelegate extends PersistenceDelegate {

static String CLASS_PREFIX = "java.util.Collections$"; //$NON-NLS-1$

private static final String COLLECTIONS_TYPE = "type"; //$NON-NLS-1$

private static final String MAP_KEY_TYPE = "keyType"; //$NON-NLS-1$

private static final String MAP_VALUE_TYPE = "valueType"; //$NON-NLS-1$

protected boolean mutatesTo(Object o1, Object o2) {
if (BeansUtils.declaredEquals(o1.getClass())) {
return o1.equals(o2);
}
if (o1 instanceof Collection<?>) {
Collection<?> c1 = (Collection<?>) o1;
Collection<?> c2 = (Collection<?>) o2;
return c1.size() == c2.size() && c1.containsAll(c2);
}
if (o1 instanceof Map<?, ?>) {
Map<?, ?> m1 = (Map<?, ?>) o1;
Map<?, ?> m2 = (Map<?, ?>) o2;
return m1.size() == m2.size()
&& m1.entrySet().containsAll(m2.entrySet());
}
return super.mutatesTo(o1, o2);
}

@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
protected Expression instantiate(Object oldInstance, Encoder enc) {
String className = oldInstance.getClass().getName();
if (className.endsWith("UnmodifiableCollection")) { //$NON-NLS-1$
// Collections.unmodifiableCollection(Collection);
return new Expression(oldInstance, Collections.class,
"unmodifiableCollection", new Object[] { new ArrayList( //$NON-NLS-1$
(Collection) oldInstance) });
} else if (className.endsWith("UnmodifiableList")) { //$NON-NLS-1$
// Collections.unmodifiableList(List);
return new Expression(oldInstance, Collections.class,
"unmodifiableList", new Object[] { new LinkedList(
(Collection) oldInstance) });
} else if (className.endsWith("UnmodifiableRandomAccessList")) { //$NON-NLS-1$
// Collections.unmodifiableList(List);
return new Expression(oldInstance, Collections.class,
"unmodifiableList", new Object[] { new ArrayList( //$NON-NLS-1$
(Collection) oldInstance) });
} else if (className.endsWith("UnmodifiableSet")) { //$NON-NLS-1$
// Collections.unmodifiableSet(Set);
return new Expression(oldInstance, Collections.class,
"unmodifiableSet", new Object[] { new HashSet( //$NON-NLS-1$
(Set) oldInstance) });
} else if (className.endsWith("UnmodifiableSortedSet")) { //$NON-NLS-1$
// Collections.unmodifiableSortedSet(set)
return new Expression(oldInstance, Collections.class,
"unmodifiableSortedSet", new Object[] { new TreeSet( //$NON-NLS-1$
(SortedSet) oldInstance) });
} else if (className.endsWith("UnmodifiableMap")) { //$NON-NLS-1$
return new Expression(oldInstance, Collections.class,
"unmodifiableMap", new Object[] { new HashMap( //$NON-NLS-1$
(Map) oldInstance) });
} else if (className.endsWith("UnmodifiableSortedMap")) { //$NON-NLS-1$
// Collections.unmodifiableSortedMap(SortedMap);
return new Expression(oldInstance, Collections.class,
"unmodifiableSortedMap", new Object[] { new TreeMap( //$NON-NLS-1$
(Map) oldInstance) });
} else if (className.endsWith("SynchronizedCollection")) { //$NON-NLS-1$
// Collections.synchronizedCollection(Collection);
return new Expression(oldInstance, Collections.class,
"synchronizedCollection", new Object[] { new ArrayList( //$NON-NLS-1$
(Collection) oldInstance) });
} else if (className.endsWith("SynchronizedList")) { //$NON-NLS-1$
// Collections.synchronizedList(List);
return new Expression(oldInstance, Collections.class,
"synchronizedList", new Object[] { new LinkedList( //$NON-NLS-1$
(List) oldInstance) });
} else if (className.endsWith("SynchronizedRandomAccessList")) { //$NON-NLS-1$
// Collections.synchronizedList(List);
return new Expression(oldInstance, Collections.class,
"synchronizedList", new Object[] { new ArrayList( //$NON-NLS-1$
(List) oldInstance) });
} else if (className.endsWith("SynchronizedSet")) { //$NON-NLS-1$
// Collections.synchronizedSet(Set);
return new Expression(oldInstance, Collections.class,
"synchronizedSet", new Object[] { new HashSet( //$NON-NLS-1$
(Set) oldInstance) });
} else if (className.endsWith("SynchronizedSortedSet")) { //$NON-NLS-1$
// Collections.synchronizedSortedSet(SortedSet);
return new Expression(oldInstance, Collections.class,
"synchronizedSortedSet", new Object[] { new TreeSet( //$NON-NLS-1$
(SortedSet) oldInstance) });
} else if (className.endsWith("SynchronizedMap")) { //$NON-NLS-1$
// Collections.synchronizedMap(Map);
return new Expression(oldInstance, Collections.class,
"synchronizedMap", new Object[] { new HashMap( //$NON-NLS-1$
(Map) oldInstance) });
} else if (className.endsWith("SynchronizedSortedMap")) { //$NON-NLS-1$
// Collections.synchronizedSortedMap(SortedMap)
return new Expression(oldInstance, Collections.class,
"synchronizedSortedMap", new Object[] { new TreeMap( //$NON-NLS-1$
(SortedMap) oldInstance) });
} else if (className.endsWith("CheckedCollection")) { //$NON-NLS-1$
// Collections.checkedCollection(Collection, Class);
return new Expression(oldInstance, Collections.class,
"checkedCollection", new Object[] { //$NON-NLS-1$
new ArrayList((Collection) oldInstance),
valueOfField(oldInstance, COLLECTIONS_TYPE) });
} else if (className.endsWith("CheckedList")) { //$NON-NLS-1$
// Collections.checkedList(List, Class);
return new Expression(oldInstance, Collections.class,
"checkedList", new Object[] {
new LinkedList((Collection) oldInstance),
valueOfField(oldInstance, COLLECTIONS_TYPE) });
} else if (className.endsWith("CheckedRandomAccessList")) { //$NON-NLS-1$
// Collections.checkedList(List, Class);
return new Expression(oldInstance, Collections.class,
"checkedList", new Object[] { //$NON-NLS-1$
new ArrayList((Collection) oldInstance),
valueOfField(oldInstance, COLLECTIONS_TYPE) });
} else if (className.endsWith("CheckedSet")) { //$NON-NLS-1$
// Collections.checkedSet(Set, Class);
return new Expression(oldInstance, Collections.class, "checkedSet", //$NON-NLS-1$
new Object[] { new HashSet((Set) oldInstance),
valueOfField(oldInstance, COLLECTIONS_TYPE) });
} else if (className.endsWith("CheckedSortedSet")) { //$NON-NLS-1$
// Collections.checkedSortedSet(SortedSet, Class);
return new Expression(oldInstance, Collections.class,
"checkedSortedSet", new Object[] { //$NON-NLS-1$
new TreeSet((Set) oldInstance),
valueOfField(oldInstance, COLLECTIONS_TYPE) });
} else if (className.endsWith("CheckedMap")) { //$NON-NLS-1$
// Collections.checkedMap(Map, keyType, valueType);
return new Expression(oldInstance, Collections.class, "checkedMap", //$NON-NLS-1$
new Object[] { new HashMap((Map) oldInstance),
valueOfField(oldInstance, MAP_KEY_TYPE),
valueOfField(oldInstance, MAP_VALUE_TYPE) });
} else if (className.endsWith("CheckedSortedMap")) { //$NON-NLS-1$
// Collections.checkedSortedMap(SortedMap, keyType, valueType);
return new Expression(oldInstance, Collections.class,
"checkedSortedMap", new Object[] { //$NON-NLS-1$
new TreeMap((Map) oldInstance),
valueOfField(oldInstance, MAP_KEY_TYPE),
valueOfField(oldInstance, MAP_VALUE_TYPE) });
}
return null;
}

private static Object valueOfField(Object obj, String fieldName) {
Class<?> clazz = obj.getClass();
Field field = null;
while (clazz != null) {
for (Field declaredField : clazz.getDeclaredFields()) {
if (fieldName.equals(declaredField.getName())) {
field = declaredField;
break;
}
}
clazz = clazz.getSuperclass();
}
if (field != null) {
if (!field.isAccessible()) {
field.setAccessible(true);
}
try {
return field.get(obj);
} catch (Exception e) {
// Ignored
}
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,8 @@ protected void initialize(Class<?> type, Object oldInstance,
Object targetVal = enc.get(oldVal);
Object newVal = new Expression(newInstance, getter.getName(),
null).getValue();
boolean invokeSetter = targetVal == null ? (newVal != null && oldVal == null)
: !enc.getPersistenceDelegate(targetVal.getClass())
.mutatesTo(targetVal, newVal);
if (invokeSetter) {
if (targetVal == null ? (newVal != null && oldVal == null)
: targetVal != newVal && !targetVal.equals(newVal)) {
enc.writeStatement(new Statement(oldInstance, setter
.getName(), new Object[] { oldVal }));
}
Expand Down
28 changes: 18 additions & 10 deletions classlib/modules/beans/src/main/java/java/beans/Encoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ public class Encoder {

private static final LangEnumPersistenceDelegate langEnumPD = new LangEnumPersistenceDelegate();

private static final UtilCollectionsPersistenceDelegate utilCollectionsPD = new UtilCollectionsPersistenceDelegate();

private static final ArrayPersistenceDelegate arrayPD = new ArrayPersistenceDelegate();

private static final ProxyPersistenceDelegate proxyPD = new ProxyPersistenceDelegate();
Expand Down Expand Up @@ -105,6 +107,19 @@ public void exceptionThrown(Exception exception) {
delegates.put(String.class, new StringPersistenceDelegate());
delegates.put(Proxy.class, new ProxyPersistenceDelegate());
delegates.put(Date.class, new UtilDatePersistenceDelegate());

PersistenceDelegate pd = new UtilListPersistenceDelegate();
delegates.put(java.util.List.class, pd);
delegates.put(java.util.AbstractList.class, pd);

pd = new UtilCollectionPersistenceDelegate();
delegates.put(java.util.Collection.class, pd);
delegates.put(java.util.AbstractCollection.class, pd);

pd = new UtilMapPersistenceDelegate();
delegates.put(java.util.Map.class, pd);
delegates.put(java.util.AbstractMap.class, pd);
delegates.put(java.util.Hashtable.class, pd);
}

private ExceptionListener listener = defaultExListener;
Expand Down Expand Up @@ -208,16 +223,9 @@ public PersistenceDelegate getPersistenceDelegate(Class<?> type) {
return registeredPD;
}

if (java.util.List.class.isAssignableFrom(type)) {
return new UtilListPersistenceDelegate();
}

if (java.util.Collection.class.isAssignableFrom(type)) {
return new UtilCollectionPersistenceDelegate();
}

if (java.util.Map.class.isAssignableFrom(type)) {
return new UtilMapPersistenceDelegate();
if (type.getName().startsWith(
UtilCollectionsPersistenceDelegate.CLASS_PREFIX)) {
return utilCollectionsPD;
}

if (type.isArray()) {
Expand Down
Loading

0 comments on commit 5780971

Please sign in to comment.