1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-22 06:02:11 +02:00

Bug 489553 - ConcurrentModificationException below

MapProblemPreference.clone

Change-Id: If80417f386890495961745d13b3ad16040677e2e
This commit is contained in:
Alena Laskavaia 2016-03-14 11:17:07 -04:00 committed by Gerrit Code Review @ Eclipse.org
parent 6a7969bc85
commit d8a5d3cc0e
2 changed files with 47 additions and 37 deletions

View file

@ -12,9 +12,12 @@ package org.eclipse.cdt.codan.core.param;
import java.io.IOException; import java.io.IOException;
import java.io.StreamTokenizer; import java.io.StreamTokenizer;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.cdt.codan.core.model.AbstractCheckerWithProblemPreferences; import org.eclipse.cdt.codan.core.model.AbstractCheckerWithProblemPreferences;
@ -30,9 +33,9 @@ import org.eclipse.cdt.codan.core.model.AbstractCheckerWithProblemPreferences;
* *
* @noextend This class is not intended to be extended by clients. * @noextend This class is not intended to be extended by clients.
*/ */
public class MapProblemPreference extends AbstractProblemPreference implements IProblemPreferenceCompositeValue, public class MapProblemPreference extends AbstractProblemPreference
IProblemPreferenceCompositeDescriptor { implements IProblemPreferenceCompositeValue, IProblemPreferenceCompositeDescriptor {
protected LinkedHashMap<String, IProblemPreference> hash = new LinkedHashMap<String, IProblemPreference>(); private Map<String, IProblemPreference> hash = Collections.synchronizedMap(new LinkedHashMap<String, IProblemPreference>());
/** /**
* Default constructor * Default constructor
@ -123,30 +126,34 @@ public class MapProblemPreference extends AbstractProblemPreference implements I
@Override @Override
public Object clone() { public Object clone() {
MapProblemPreference map = (MapProblemPreference) super.clone(); MapProblemPreference map = (MapProblemPreference) super.clone();
map.hash = new LinkedHashMap<String, IProblemPreference>(); synchronized (hash) {
for (Iterator<String> iterator = hash.keySet().iterator(); iterator.hasNext();) { map.hash = Collections.synchronizedMap(new LinkedHashMap<String, IProblemPreference>(hash));
String key = iterator.next(); }
map.hash.put(key, (IProblemPreference) hash.get(key).clone()); // now we have to clone the values too
for (Entry<String, IProblemPreference> entry : map.hash.entrySet()) {
entry.setValue((IProblemPreference) entry.getValue().clone());
} }
return map; return map;
} }
@Override @Override
public String exportValue() { public String exportValue() {
StringBuffer buf = new StringBuffer("{"); //$NON-NLS-1$ synchronized (hash) {
for (Iterator<String> iterator = hash.keySet().iterator(); iterator.hasNext();) { StringBuffer buf = new StringBuffer("{"); //$NON-NLS-1$
String key = iterator.next(); for (Iterator<String> iterator = hash.keySet().iterator(); iterator.hasNext();) {
IProblemPreference d = hash.get(key); String key = iterator.next();
if (d instanceof AbstractProblemPreference) { IProblemPreference d = hash.get(key);
if (((AbstractProblemPreference) d).isDefault()) { if (d instanceof AbstractProblemPreference) {
continue; if (((AbstractProblemPreference) d).isDefault()) {
continue;
}
} }
buf.append(key + "=>" + d.exportValue()); //$NON-NLS-1$
if (iterator.hasNext())
buf.append(","); //$NON-NLS-1$
} }
buf.append(key + "=>" + d.exportValue()); //$NON-NLS-1$ return buf.toString() + "}"; //$NON-NLS-1$
if (iterator.hasNext())
buf.append(","); //$NON-NLS-1$
} }
return buf.toString() + "}"; //$NON-NLS-1$
} }
@Override @Override
@ -243,12 +250,14 @@ public class MapProblemPreference extends AbstractProblemPreference implements I
*/ */
@Override @Override
public Object getValue() { public Object getValue() {
LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>(); synchronized (hash) {
for (Iterator<IProblemPreference> iterator = hash.values().iterator(); iterator.hasNext();) { LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>();
IProblemPreference pref = iterator.next(); for (Iterator<IProblemPreference> iterator = hash.values().iterator(); iterator.hasNext();) {
map.put(pref.getKey(), pref.getValue()); IProblemPreference pref = iterator.next();
map.put(pref.getKey(), pref.getValue());
}
return map;
} }
return map;
} }
/** /**
@ -263,19 +272,21 @@ public class MapProblemPreference extends AbstractProblemPreference implements I
@Override @Override
public void setValue(Object value) { public void setValue(Object value) {
Map<String, Object> map = (Map<String, Object>) value; Map<String, Object> map = (Map<String, Object>) value;
LinkedHashMap<String, IProblemPreference> hash2 = (LinkedHashMap<String, IProblemPreference>) hash.clone(); synchronized (hash) {
hash.clear(); Map<String, IProblemPreference> hashCopy = new HashMap<>(hash);
for (Iterator<String> iterator = map.keySet().iterator(); iterator.hasNext();) { hash.clear();
String key = iterator.next(); for (Iterator<String> iterator = map.keySet().iterator(); iterator.hasNext();) {
Object value2 = map.get(key); String key = iterator.next();
if (value2 instanceof IProblemPreference) { Object value2 = map.get(key);
hash.put(key, (IProblemPreference) value2); if (value2 instanceof IProblemPreference) {
} else { hash.put(key, (IProblemPreference) value2);
IProblemPreference pref = hash2.get(key); } else {
addChildDescriptor(pref); IProblemPreference pref = hashCopy.get(key);
//setChildValue(key, value2); addChildDescriptor(pref);
pref.setValue(value2); //setChildValue(key, value2);
hash.put(key, pref); pref.setValue(value2);
hash.put(key, pref);
}
} }
} }
} }

View file

@ -20,7 +20,6 @@ public class SharedRootProblemPreference extends RootProblemPreference {
public Object clone() { public Object clone() {
SharedRootProblemPreference map = (SharedRootProblemPreference) super.clone(); SharedRootProblemPreference map = (SharedRootProblemPreference) super.clone();
// alruiz: sharing the internal hash is the only way I could make this work. // alruiz: sharing the internal hash is the only way I could make this work.
map.hash = hash;
return map; return map;
} }
} }