JAXB Marshalling e Genéricos
Pergunta
Eu estou tentando usar introspecção do JAXB para Marshall e unmashall algum domínio existente objetos marcados com anotações JAXB. A maioria das coisas funcionam conforme o esperado, mas estou tendo um pouco de dificuldade para obter uma classe bastante simples de serialize. Esta classe é usada como um @XmlElement de uma série de feijão e é algo como:
public class Range<E extends Comparable<E>> implements Serializable {
protected boolean startInclusive, endInclusive;
protected E start, end;
public Range(){
startInclusive = endInclusive = true;
}
public boolean contains(E value){...}
public E getEnd() {
return end;
}
public void setEnd(E end) {
this.end = end;
}
public boolean isEndInclusive() {
return endInclusive;
}
public void setEndInclusive(boolean endInclusive) {
this.endInclusive = endInclusive;
}
public E getStart() {
return start;
}
public void setStart(E start) {
this.start = start;
}
public boolean isStartInclusive() {
return startInclusive;
}
public void setStartInclusive(boolean startInclusive) {
this.startInclusive = startInclusive;
}
}
Eu tentei fazer o seguinte, sem sucesso, JAXB ainda está irritado com a interface Comparable.
public class DoubleRange extends Range<Double> {}
O uso de ambos Gama e DoubleRange como tipos de retorno para os rendimentos do getter feijão uma exceção como:
java.lang.Comparable is an interface, and JAXB can't handle interfaces. this problem is related to the following location: at java.lang.Comparable at protected java.lang.Comparable com.controlpath.util.Range.start at example.util.Range at example.util.DoubleRange at public example.util.DoubleRange example.domain.SomeBean.getRange() at example.domain.SomeBean
Eu percebo que na maioria dos casos List
Solução
Você poderia escrever um adaptador personalizado (não usando XMLAdapter do JAXB) fazendo o seguinte:
1) declarar uma classe que aceita todos os tipos de elementos e tem anotações JAXB e manipula-los como você deseja (no meu exemplo, eu converter tudo para String)
@YourJAXBAnnotationsGoHere
public class MyAdapter{
@XmlElement // or @XmlAttribute if you wish
private String content;
public MyAdapter(Object input){
if(input instanceof String){
content = (String)input;
}else if(input instanceof YourFavoriteClass){
content = ((YourFavoriteClass)input).convertSomehowToString();
}else if(input instanceof .....){
content = ((.....)input).convertSomehowToString();
// and so on
}else{
content = input.toString();
}
}
}
// I would suggest to use a Map<Class<?>,IMyObjToStringConverter> ...
// to avoid nasty if-else-instanceof things
2) usar esta classe em vez de E em sua classe a-ser-marshalled
NOTAS
- É claro que esta faria não trabalho para complexos (aninhados) estruturas de dados.
- Você tem que pensar como desempacotar esta de volta, poderia ser mais complicado. E se é muito complicado, espera por uma proposta melhor do que o meu;)
Outras dicas
Como cerca
public class Range<**E extends Number**> implements Serializable { ...
-
Número é um class
-
Eu aposto JAXB sabe padrão triagem / unmarshalling regras para o número
Para unmarshalling de tipo específico, você precisa XMLAdapter como eu descrito aqui: JAXB herança, desempacotar a subclasse da classe empacotada
Tente algo como serialização XML simples ele vem com suporte para tipos genéricos em elementos XML com uma série de anotações tal como @Element e @ElementList. O modelo de programação é muito semelhante, mas mais simples do que JAXB.
Na verdade, não é muito claro para mim por que isso não iria funcionar. Parece que JAXB deve ser capaz de resolver subtipo específico corretamente: if (! E somente se) deste tipo não é o tipo de raiz (o que não é de acordo com sua descrição). Quero dizer, é apenas um feijão; por isso, se de feijão com T substituído com obras tipo direto, por isso deve versão genérica sse usando sub-classes para tipos de vinculação (como é feito no exemplo).
Por isso, talvez ele poderia ser um bug na implementação?
Portanto, parece que o problema é o apagamento de E
em start
e end
é Comparable
. Se ele não consegue lidar com interfaces de você poderia tentar Object
, mas eu espero que reclama a isso também (agora ou mais tarde). Possivelmente você poderia fazer Range
abstrato e especializar-lo para cada E
específico. Eu deveria saber mais sobre JAXB.