Giter Site home page Giter Site logo

Comments (7)

adbrown85 avatar adbrown85 commented on June 29, 2024

Source files:

Renderer.java

interface Renderer {
    // empty
}

CircleRenderer.java

class CircleRenderer implements Renderer {
    // empty
}

Table.java

import java.util.LinkedHashMap;
import java.util.Map;

class Table {

   private Map<String, Renderer> renderers = new LinkedHashMap<>();

   Table() {
      // empty
   }

   Map<String, Renderer> getRenderers() {
      return new LinkedHashMap<>(renderers);
   }    

   void setRenderer(String column, Renderer renderer) {
      renderers.put(column, renderer);
   }
}

TableConverter.java

import com.thoughtworks.xstream.converters.ConversionException;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

import java.util.Map;

class TableConverter implements Converter {

    private String lastNodeName = null;

    TableConverter() {
        // empty
    }

    @Override
    public boolean canConvert(Class clazz) {
        return Table.class.equals(clazz);
    }

    String getLastNodeName() {
        return lastNodeName;
    }

    @Override
    public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) {

        Table table = (Table) value;

        writer.startNode("renderers");
        context.convertAnother(table.getRenderers());
        writer.endNode();
    }

    @Override
    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {

        Table table = new Table();

        reader.moveDown();
        try {
            unmarshalRenderers(reader, context, table);
        } catch (ConversionException e) {
            // log exception
        } finally {
            reader.moveUp();
        }

        lastNodeName = reader.getNodeName();

        return table;
    }

    private void unmarshalRenderers(HierarchicalStreamReader reader, UnmarshallingContext context, Table table) {

        assert reader.getNodeName().equals("renderers");

        Map<String, Renderer> renderers = (Map<String, Renderer>) context.convertAnother(null, Map.class);
        for (Map.Entry<String, Renderer> entry : renderers.entrySet()) {
            table.setRenderer(entry.getKey(), entry.getValue());
        }
    }
}

from xstream.

adbrown85 avatar adbrown85 commented on June 29, 2024

Test:

TableConverterTest.java

import static org.junit.Assert.*;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

import java.util.Map;

import org.junit.Before;
import org.junit.Test;

public class TableConverterTest {

    private XStream xstream;

    private TableConverter converter;

    @Before
    public void setUp() {
        xstream = new XStream();
        converter = new TableConverter();
        xstream.registerConverter(converter);
    }

    @Test
    public void testMarshal() {

        final Table table = new Table();
        table.setRenderer("foo", new CircleRenderer());
        table.setRenderer("bar", new CircleRenderer());

        assertEquals(
                "<Table>\n" +
                "  <renderers>\n" +
                "    <entry>\n" +
                "      <string>foo</string>\n" +
                "      <CircleRenderer/>\n" +
                "    </entry>\n" +
                "    <entry>\n" +
                "      <string>bar</string>\n" +
                "      <CircleRenderer/>\n" +
                "    </entry>\n" +
                "  </renderers>\n" +
                "</Table>",
                xstream.toXML(table)
        );
    }

    @Test
    public void testUnmarshalWithCircleRenderer() {
        xstream.fromXML(
                "<Table>\n" +
                "  <renderers>\n" +
                "    <entry>\n" +
                "      <string>foo</string>\n" +
                "      <CircleRenderer/>\n" +
                "    </entry>\n" +
                "  </renderers>\n" +
                "</Table>"
        );
        assertEquals("Table", converter.getLastNodeName());
    }

    @Test
    public void testUnmarshalWithSquareRenderer() {
        xstream.fromXML(
                "<Table>\n" +
                "  <renderers>\n" +
                "    <entry>\n" +
                "      <string>foo</string>\n" +
                "      <SquareRenderer/>\n" + // doesn't exist
                "    </entry>\n" +
                "  </renderers>\n" +
                "</Table>"
        );
        assertEquals("Table", converter.getLastNodeName());
    }
}

from xstream.

adbrown85 avatar adbrown85 commented on June 29, 2024

POM:

<project>
   <modelVersion>4.0.0</modelVersion>

   <groupId>com.thoughtworks.xstream</groupId>
   <artifactId>issue-26</artifactId>
   <version>0.1-SNAPSHOT</version>

   <properties>

      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

      <targetJdk>1.7</targetJdk>

   </properties>

   <dependencies>

      <dependency>
         <groupId>com.thoughtworks.xstream</groupId>
         <artifactId>xstream</artifactId>
         <version>1.4.8</version>
      </dependency>

      <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.12</version>
      </dependency>

   </dependencies>

   <build>

      <defaultGoal>test</defaultGoal>

      <plugins>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
               <source>${targetJdk}</source>
               <target>${targetJdk}</target>
            </configuration>
         </plugin>
      </plugins>
   </build>

</project>

from xstream.

joehni avatar joehni commented on June 29, 2024

The input stream is for XStream in an undefined state after an exception. XStream does not make any agreements after an exception is raised.

Any converter (not only XStream's) would have to obey a contract that an even call of the moveDown/moveUp have been made at the exit of the unmarshal method.

from xstream.

joehni avatar joehni commented on June 29, 2024

What you can do instead is to derive a custom converter from MapConverter and overload putCurrentEntryIntoMap that can ignore the exception adds no element to the map in that case.

from xstream.

adbrown85 avatar adbrown85 commented on June 29, 2024

Thanks for your quick reply Jörg.

I understand in the general case when you don't really know what converters you're working with there's basically nothing you can do short of maybe creating a separate XStream instance and trying to serialize it out separately beforehand.

That being said, do you think there would still be value in making XStream's stock map converter (and maybe others) at least make a best effort to recover?

I'm working on a contract right now where the customer needs to be able to recover from missing items in the input file, and we will probably just put in a separate check before like I mentioned to be sure, or in this specific case just serialize the items out differently.

However, I was thinking there may be others that come along who might find it helpful if they didn't have to do anything extra, especially if they're only working with the stock XStream converters.

Or do you think that having the XStream converters recover would potentially be misleading?

from xstream.

joehni avatar joehni commented on June 29, 2024

I am a bit hesitant to improve the situation, because XStream will never be able to guarantee something. Basically, XStream is Java to XML and back, i.e. normally is never something unknown in the XML. ;-)

However, for your special case, I'd really register a custom MapConverter with the modification proposed above. For fields you may use omitField or ignoreUnknownElements, unfortunately these settings do not apply to elements of lists or maps.

from xstream.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.