У меня есть следующий XML:
<rootElement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<collection>
<link referenceId="id1" foo="foo"/>
</collection>
<referencable id="id1" name="bar"/>
</rootElement>
Я написал несколько классов, к которым этот XML должен быть распакован через JAXB (код ниже).Обратите внимание на следующие моменты:
Link
имеет переопределенные методы equals
и getHashCode
.Указанный объект (заданный referenceId
) влияет на хеш-код.Это означает, что A Link
без установленного referenceId
имеет хеш-код, отличный от установленного referenceId
.
Collection
содержитHashSet<Link>
, который заполняется Link
с во время демаршаллинга.Это означает: A Link
, который был помещен в Set
, не должен впоследствии изменять свой хэш-код;иначе он не будет найден методом contains
!
При отмене вызова с помощью следующего кода
InputStream is = new FileInputStream("C:\\rootElement.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(RootElement.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
RootElement rootElement = (RootElement)jaxbUnmarshaller.unmarshal(is);
Link
заканчиваетсявверх неразборчиво, что можно легко увидеть, позвонив по номеру
Set<Link> links = rootElement.getCollection().getLink();
boolean contains = links.contains(links.iterator().next()); // returns false
Так что мой вопрос: Как я могу убедиться, что Link
добавляется только к HashSet<Link>
ПОСЛЕ его referenceId
был установлен?
Изменение XML не является вариантом;Я получаю его от третьей стороны и не могу его изменять *.(Переключение элементов collection
и referencable
решит проблему, потому что тогда Link
получает свой referenceId
, установленный до того, как он будет добавлен в Set<Link>
.)
Изменение HashSet
на какую-либо коллекцию, в которой не используется getHashCode
, не вариант;Мне нужен contains
метод с O(1)
производительностью *.
Изменение getHashCode
метода Link
не вариант;Мне это нужно.В противном случае он становится бесполезным.
* Сценарий реальной жизни связан с огромными XML-файлами, в которых коллекция содержит тысячи ссылок.
RootElement:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"collection",
"referencable"
})
@XmlRootElement(name = "rootElement")
public class RootElement {
protected Collection collection;
protected Referencable referencable;
public Referencable getReferencable() { return referencable; }
public void setReferencable(Referencable referencable) { this.referencable = referencable; }
public Collection getCollection() { return collection; }
public void setCollection(Collection collection) { this.collection = collection; }
}
Коллекция:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Collection", propOrder = {"link"})
public class Collection {
protected Set<Link> link;
public Set<Link> getLink() {
if (link == null) { link = new HashSet<Link>(); }
return this.link;
}
}
Ссылка:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Link")
public class Link
{
@XmlAttribute(name = "referenceId", required = true)
@XmlIDREF
@XmlSchemaType(name = "IDREF")
protected Object referenceId;
public Object getReferenceId() { return referenceId; }
public void setReferenceId(Object value) { this.referenceId = value; }
@XmlAttribute(name = "foo", required = true)
protected String foo;
public String getFoo() { return foo; }
public void setFoo(String foo) { this.foo = foo; }
@Override public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((foo == null) ? 0 : foo.hashCode());
result = prime * result + ((referenceId == null) ? 0 : referenceId.hashCode());
return result;
}
@Override public boolean equals(Object obj) {
if (this == obj) { return true; }
if (obj == null) { return false; }
if (getClass() != obj.getClass()) { return false; }
Link other = (Link) obj;
if (foo == null) { if (other.foo != null) { return false; } }
else if (!foo.equals(other.foo)) { return false; }
if (referenceId == null) { if (other.referenceId != null) { return false; } }
else if (!referenceId.equals(other.referenceId)) { return false; }
return true;
}
}
Ссылка:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Referencable")
public class Referencable
{
@XmlAttribute(name = "id", required = true)
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
@XmlID
@XmlSchemaType(name = "ID")
protected String id;
public String getId() { return id; }
public void setId(String value) { this.id = value; }
@XmlAttribute(name = "name")
protected String name;
public String getName() { return name; }
public void setName(String value) { this.name = value; }
@Override public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override public boolean equals(Object obj) {
if (this == obj) { return true; }
if (!super.equals(obj)) { return false; }
if (getClass() != obj.getClass()) { return false; }
Referencable other = (Referencable) obj;
if (name == null) { if (other.name != null) { return false; } }
else if (!name.equals(other.name)) { return false; }
return true;
}
}