Search code examples
javaxmlxstream

Xstream field with converter is not an attribute even with @XStreamAsAttribute


I try to marshal an object and I want all the fields to be attributes. The normal fields are OK with the @XStreamAsAttribute annotation but I have two of them with a converter. For them when I marshal they are converted as field...

@XStreamAlias(value="sinistre")
public class ObjetMetierSinistreDto {

    @XStreamAlias(value="S_sinistreEtat")
    @XStreamAsAttribute
    private String etat;

    @XStreamAsAttribute
    @XStreamAlias(value="S_sinistreDateSurv")
    @XStreamConverter(value=JodaDateConverter.class)
    private LocalDate dateSurvenanceDossier;
...

The converter:

public class JodaDateConverter implements Converter {

@Override
@SuppressWarnings("unchecked")
public boolean canConvert(final Class type) {
      return (type != null) && LocalDate.class.getPackage().equals(type.getPackage());
}

@Override
public void marshal(final Object source, final HierarchicalStreamWriter writer,
      final MarshallingContext context) {
      writer.setValue(source.toString().replace("-", "/"));
}

@Override
@SuppressWarnings("unchecked")
public Object unmarshal(final HierarchicalStreamReader reader,
      final UnmarshallingContext context) {
      try {
              final Class requiredType = context.getRequiredType();
              final Constructor constructor = requiredType.getConstructor(Object.class);
              return constructor.newInstance(reader.getValue());
      } catch (final Exception e) {
          throw new RuntimeException(String.format(
           "Exception while deserializing a Joda Time object: %s", context.getRequiredType().getSimpleName()), e);
      }
}

}

and the result:

<sinistre S_sinistreEtat="S">        
  <S_sinistreDateSurv>2015/02/01</S_sinistreDateSurv>
</sinistre>

and what I like:

<sinistre S_sinistreEtat="S"
          S_sinistreDateSurv="2015/02/01"/>

Solution

  • I finally found how to solve this problem!

    The JodaDateConverter should not implements Converter but extends AbstractSingleValueConverter (as the DateConverter from XStream)

    Then you just need to override canConvert() and fromString() and you are good to go!

    Exemple:

    public class JodaDateConverter extends AbstractSingleValueConverter {
    
    
    
     @Override
      @SuppressWarnings("unchecked")
      public boolean canConvert(final Class type) {
              return (type != null) && LocalDate.class.getPackage().equals(type.getPackage());
      }
    
      @Override
      public Object fromString(String str) {
        String separator;
        if(str.contains(":")){
          separator = ":";
        } else if(str.contains("/")){
          separator = "/";
        } else if(str.contains("-")){
          separator = "-";
        } else {
          throw new RuntimeException("The date must contains ':' or '/' or '-'");
        }
        String[] date = str.split(separator);
        if(date.length < 3){
          throw new RuntimeException("The date must contains hour, minute and second");
        }
        return new LocalDate(Integer.valueOf(date[0]),Integer.valueOf(date[1]),Integer.valueOf(date[2]));
      }
    
    }