mirror of https://github.com/apache/openjpa.git
OPENJPA-305: Add originalValue for Value and modify Configuration equality/hashCode to base on Value equality/hashCode
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@577164 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
7524219f6a
commit
cea8ab57d1
|
@ -778,8 +778,9 @@ public class ConfigurationImpl
|
||||||
/////////////
|
/////////////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs an equality check based on the properties returned from
|
* Performs an equality check based on equality of values.
|
||||||
* {@link #toProperties}.
|
* {@link Value#equals(Object) Equality} of Values varies if the Value is
|
||||||
|
* {@link Value#isDynamic() dynamic}.
|
||||||
*/
|
*/
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if (other == this)
|
if (other == this)
|
||||||
|
@ -791,18 +792,32 @@ public class ConfigurationImpl
|
||||||
|
|
||||||
// compare properties
|
// compare properties
|
||||||
ConfigurationImpl conf = (ConfigurationImpl) other;
|
ConfigurationImpl conf = (ConfigurationImpl) other;
|
||||||
Map p1 = (_props == null) ? toProperties(false) : _props;
|
if (_vals.size() != conf.getValues().length)
|
||||||
Map p2 = (conf._props == null) ? conf.toProperties(false) : conf._props;
|
return false;
|
||||||
return excludeDynamic(p1).equals(excludeDynamic(p2));
|
Iterator values = _vals.iterator();
|
||||||
|
while (values.hasNext()) {
|
||||||
|
Value v = (Value)values.next();
|
||||||
|
Value thatV = conf.getValue(v.getProperty());
|
||||||
|
if (!v.equals(thatV)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes hash code based on the properties returned from
|
* Computes hash code based on the hashCodes of the values.
|
||||||
* {@link #toProperties}.
|
* {@link Value#hashCode() HashCode} of a Value varies if the Value is
|
||||||
|
* {@link Value#isDynamic() dynamic}.
|
||||||
*/
|
*/
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
Map copy = (_props == null) ? toProperties(false) : _props;
|
Iterator values = _vals.iterator();
|
||||||
return excludeDynamic(copy).hashCode();
|
int hash = 0;
|
||||||
|
while (values.hasNext()) {
|
||||||
|
Value v = (Value)values.next();
|
||||||
|
hash += v.hashCode();
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -978,16 +993,4 @@ public class ConfigurationImpl
|
||||||
addValue(val);
|
addValue(val);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map excludeDynamic(Map map) {
|
|
||||||
if (map == null)
|
|
||||||
return null;
|
|
||||||
Map copy = new HashMap(map);
|
|
||||||
Value[] values = getValues();
|
|
||||||
for (int i=0; i<values.length; i++) {
|
|
||||||
if (values[i].isDynamic())
|
|
||||||
Configurations.removeProperty(values[i].getProperty(), copy);
|
|
||||||
}
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,7 +110,8 @@ public class PluginListValue extends ObjectValue {
|
||||||
for (int i = 0; i < _names.length; i++) {
|
for (int i = 0; i < _names.length; i++) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
buf.append(", ");
|
buf.append(", ");
|
||||||
buf.append(Configurations.getPlugin(alias(_names[i]), _props[i]));
|
buf.append(Configurations.getPlugin(alias(_names[i]),
|
||||||
|
(i<_props.length) ? _props[i] : null));
|
||||||
}
|
}
|
||||||
if (buf.length() == 0)
|
if (buf.length() == 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.apache.openjpa.lib.util.ParseException;
|
||||||
* A configuration value.
|
* A configuration value.
|
||||||
*
|
*
|
||||||
* @author Marc Prud'hommeaux
|
* @author Marc Prud'hommeaux
|
||||||
|
* @author Pinaki Poddar (added dynamic Value support)
|
||||||
*/
|
*/
|
||||||
public abstract class Value implements Cloneable {
|
public abstract class Value implements Cloneable {
|
||||||
|
|
||||||
|
@ -44,6 +45,7 @@ public abstract class Value implements Cloneable {
|
||||||
private boolean aliasListComprehensive = false;
|
private boolean aliasListComprehensive = false;
|
||||||
private Class scope = null;
|
private Class scope = null;
|
||||||
private boolean isDynamic = false;
|
private boolean isDynamic = false;
|
||||||
|
private String originalValue = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor.
|
* Default constructor.
|
||||||
|
@ -278,12 +280,22 @@ public abstract class Value implements Cloneable {
|
||||||
* empty and a default is defined, the default is used. If the given
|
* empty and a default is defined, the default is used. If the given
|
||||||
* string(or default) is an alias key, it will be converted to the
|
* string(or default) is an alias key, it will be converted to the
|
||||||
* corresponding value internally.
|
* corresponding value internally.
|
||||||
|
* <br>
|
||||||
|
* If this Value is being set to a non-default value for the first time
|
||||||
|
* (as designated by <code>originalString</code> being null), then the
|
||||||
|
* value is remembered as <em>original</em>. This original value is used
|
||||||
|
* for equality and hashCode computation if this Value is
|
||||||
|
* {@link #isDynamic() dynamic}.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public void setString(String val) {
|
public void setString(String val) {
|
||||||
assertChangeable();
|
assertChangeable();
|
||||||
String str = unalias(val);
|
String str = unalias(val);
|
||||||
try {
|
try {
|
||||||
setInternalString(str);
|
setInternalString(str);
|
||||||
|
if (originalValue == null && val != null && !isDefault(val)) {
|
||||||
|
originalValue = getString();
|
||||||
|
}
|
||||||
} catch (ParseException pe) {
|
} catch (ParseException pe) {
|
||||||
throw pe;
|
throw pe;
|
||||||
} catch (RuntimeException re) {
|
} catch (RuntimeException re) {
|
||||||
|
@ -293,6 +305,13 @@ public abstract class Value implements Cloneable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set this value as an object.
|
* Set this value as an object.
|
||||||
|
* <br>
|
||||||
|
* If this Value is being set to a non-default value for the first time
|
||||||
|
* (as designated by <code>originalString</code> being null), then the
|
||||||
|
* value is remembered as <em>original</em>. This original value is used
|
||||||
|
* for equality and hashCode computation if this Value is
|
||||||
|
* {@link #isDynamic() dynamic}.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public void setObject(Object obj) {
|
public void setObject(Object obj) {
|
||||||
// if setting to null set as string to get defaults into play
|
// if setting to null set as string to get defaults into play
|
||||||
|
@ -301,6 +320,9 @@ public abstract class Value implements Cloneable {
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
setInternalObject(obj);
|
setInternalObject(obj);
|
||||||
|
if (originalValue == null && obj != null && !isDefault(obj)) {
|
||||||
|
originalValue = getString();
|
||||||
|
}
|
||||||
} catch (ParseException pe) {
|
} catch (ParseException pe) {
|
||||||
throw pe;
|
throw pe;
|
||||||
} catch (RuntimeException re) {
|
} catch (RuntimeException re) {
|
||||||
|
@ -309,6 +331,22 @@ public abstract class Value implements Cloneable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the original value. Original value denotes the Stringified form of
|
||||||
|
* this Value, from which it has been set, if ever. If this Value has never
|
||||||
|
* been set to a non-default value, then returns the default value, which
|
||||||
|
* itself can be null.
|
||||||
|
*
|
||||||
|
* @since 1.1.0
|
||||||
|
*/
|
||||||
|
public String getOriginalValue() {
|
||||||
|
return (originalValue == null) ? getDefault() : originalValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isDefault(Object val) {
|
||||||
|
return val != null && val.toString().equals(getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the type of the property that this Value represents.
|
* Returns the type of the property that this Value represents.
|
||||||
*/
|
*/
|
||||||
|
@ -374,6 +412,7 @@ public abstract class Value implements Cloneable {
|
||||||
* Sets if this receiver can be mutated even when the configuration it
|
* Sets if this receiver can be mutated even when the configuration it
|
||||||
* belongs to has been {@link Configuration#isReadOnly() frozen}.
|
* belongs to has been {@link Configuration#isReadOnly() frozen}.
|
||||||
*
|
*
|
||||||
|
* @since 1.1.0
|
||||||
*/
|
*/
|
||||||
public void setDynamic(boolean flag) {
|
public void setDynamic(boolean flag) {
|
||||||
isDynamic = flag;
|
isDynamic = flag;
|
||||||
|
@ -383,18 +422,31 @@ public abstract class Value implements Cloneable {
|
||||||
* Affirms if this receiver can be mutated even when the configuration it
|
* Affirms if this receiver can be mutated even when the configuration it
|
||||||
* belongs to has been {@link Configuration#isReadOnly() frozen}.
|
* belongs to has been {@link Configuration#isReadOnly() frozen}.
|
||||||
*
|
*
|
||||||
|
* @since 1.1.0
|
||||||
*/
|
*/
|
||||||
public boolean isDynamic() {
|
public boolean isDynamic() {
|
||||||
return isDynamic;
|
return isDynamic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use {@link #getOriginalValue() original value} instead of
|
||||||
|
* {@link #getString() current value} because they are one and the same
|
||||||
|
* for non-dynamic Values and ensures that modifying dynamic Values do not
|
||||||
|
* impact equality or hashCode contract.
|
||||||
|
*/
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
String str = getString();
|
String str = (isDynamic()) ? getOriginalValue() : getString();
|
||||||
int strHash = (str == null) ? 0 : str.hashCode();
|
int strHash = (str == null) ? 0 : str.hashCode();
|
||||||
int propHash = (prop == null) ? 0 : prop.hashCode();
|
int propHash = (prop == null) ? 0 : prop.hashCode();
|
||||||
return strHash ^ propHash;
|
return strHash ^ propHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use {@link #getOriginalValue() original value} instead of
|
||||||
|
* {@link #getString() current value} because they are one and the same
|
||||||
|
* for non-dynamic Values and ensures that modifying dynamic Values do not
|
||||||
|
* impact equality or hashCode contract.
|
||||||
|
*/
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if (other == this)
|
if (other == this)
|
||||||
return true;
|
return true;
|
||||||
|
@ -402,8 +454,11 @@ public abstract class Value implements Cloneable {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Value o = (Value) other;
|
Value o = (Value) other;
|
||||||
return StringUtils.equals(prop, o.getProperty())
|
String thisStr = (isDynamic()) ? getOriginalValue() : getString();
|
||||||
&& StringUtils.equals(getString(), o.getString());
|
String thatStr = (isDynamic()) ? o.getOriginalValue() : o.getString();
|
||||||
|
return (isDynamic() == o.isDynamic())
|
||||||
|
&& StringUtils.equals(prop, o.getProperty())
|
||||||
|
&& StringUtils.equals(thisStr, thatStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object clone() {
|
public Object clone() {
|
||||||
|
|
Loading…
Reference in New Issue