XStream
  1. XStream
  2. XSTR-87

Field names cannot contain $ chars

    Details

    • Type: Bug Bug
    • Status: Closed Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: 1.0.2
    • Component/s: Converters
    • Labels:
      None

      Description

      Below is the thread from the mailing list.

      ----------
      Hi,

      I fixed, in a way

      please let me know about new release or something
      I'd like to see standard xstream working

      thank you,
      Slavic

      Veaceslav Chicu wrote:

      > XppReader.read()
      > here, we can decode
      >
      >
      > PrettyPrintWriter.startNode
      > here we can encode
      >
      > the problem is Basic class like
      >
      > class Person

      { > private String first_name = "Slavic"; > private String last_name = "Chicu"; > }

      >
      > doesn't work so bug is major
      >
      >
      > any idea?
      >
      >
      > best regards,
      > Slavic
      >
      >
      > Veaceslav Chicu wrote:
      >
      >> http://www.w3.org/TR/2000/REC-xml-20001006#sec-starttags
      >> so "$" is not allowed for name attribute
      >>
      >> http://java.sun.com/docs/books/jls/second_edition/html/lexical.doc.html#40625
      >> identifier can be "$"
      >>
      >> so, maybe the best is to translate characters in xml writer/reader?
      >>
      >> the list is active? or not?
      >>
      >>
      >> best regards,
      >> Slavic
      >>
      >>
      >>
      >> Veaceslav Chicu wrote:
      >>
      >>> it's xpp3 parser, he doesn't accept "$" in tag name
      >>> the problem is I have a field with "$" in name
      >>>
      >>> maybe xstream should encode/decode field names? from java allowed chars alphabet to xml tag name allowed chars alphabet?
      >>>
      >>> any suggestion?
      >>>
      >>> thank you,
      >>> Slavic
      >>>
      >>>
      >>> Veaceslav Chicu wrote:
      >>>
      >>>> Hi,
      >>>>
      >>>> I have an error importing a class,
      >>>>
      >>>> xml fragment:
      >>>> <CGLIB$CALLBACK_0 class="net.sf.hibernate.proxy.CGLIBLazyInitializer">
      >>>>
      >>>> it's because of "$"
      >>>>
      >>>> any suggestion, workaround, what can I do with this?
      >>>>
      >>>> I exported like this:
      >>>> XStream xstream = new XStream();
      >>>> String xml = xstream.toXML(lst);
      >>>>
      >>>>
      >>>> Thank you,
      >>>> Slavic
      >>>> P.S
      >>>> com.thoughtworks.xstream.converters.ConversionException: start tag unexpected character $ (position: TEXT seen ...ic.jqbe.modele.Domaine-EnhancerByCGLIB-213a5c8c"> <CGLIB$... @1:12225)
      >>>> ---- Debugging information ----
      >>>> required-type : fr.infologic.jqbe.modele.Domaine$$EnhancerByCGLIB$$213a5c8c
      >>>> cause-message : start tag unexpected character $ (position: TEXT seen ...ic.jqbe.modele.Domaine-EnhancerByCGLIB-213a5c8c"> <CGLIB$... @1:12225)
      >>>> class : java.util.List
      >>>> message : start tag unexpected character $ (position: TEXT seen ...ic.jqbe.modele.Domaine-EnhancerByCGLIB-213a5c8c"> <CGLIB$... @1:12225)
      >>>> line number : 1
      >>>> path : /list/fr.infologic.jqbe.modele.Consultation-array/fr.infologic.jqbe.modele.Consultation/domaine
      >>>> cause-exception : com.thoughtworks.xstream.io.StreamException
      >>>> -------------------------------
      >>>> at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(Unknown Source)
      >>>> at com.thoughtworks.xstream.core.ReferenceByXPathUnmarshaller.convertAnother(Unknown Source)
      >>>> at com.thoughtworks.xstream.converters.reflection.ReflectionConverter.unmarshal(Unknown Source)
      >>>> at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(Unknown Source)
      >>>> at com.thoughtworks.xstream.core.ReferenceByXPathUnmarshaller.convertAnother(Unknown Source)
      >>>> at com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.readItem(Unknown Source)
      >>>> at com.thoughtworks.xstream.converters.collections.ArrayConverter.unmarshal(Unknown Source)
      >>>> at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(Unknown Source)
      >>>> at com.thoughtworks.xstream.core.ReferenceByXPathUnmarshaller.convertAnother(Unknown Source)
      >>>> at com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.readItem(Unknown Source)
      >>>> at com.thoughtworks.xstream.converters.collections.CollectionConverter.populateCollection(Unknown Source)
      >>>> at com.thoughtworks.xstream.converters.collections.CollectionConverter.unmarshal(Unknown Source)
      >>>> at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(Unknown Source)
      >>>> at com.thoughtworks.xstream.core.ReferenceByXPathUnmarshaller.convertAnother(Unknown Source)
      >>>> at com.thoughtworks.xstream.core.TreeUnmarshaller.start(Unknown Source)
      >>>> at com.thoughtworks.xstream.core.ReferenceByXPathMarshallingStrategy.unmarshal(Unknown Source)
      >>>> at com.thoughtworks.xstream.XStream.unmarshal(Unknown Source)
      >>>> at com.thoughtworks.xstream.XStream.fromXML(Unknown Source)
      >>>> at com.thoughtworks.xstream.XStream.fromXML(Unknown Source)
      >>>>
      >>>
      >>>
      >>
      >>
      >
      >

      package com.thoughtworks.xstream.core.util;
      public class EncodeDecodeHelper {
      private final static String REPLACE_A = "AA";
      private final static String REPLACE_$ = "AD";

      public static String encodeIdentifier2XML(String identifier)

      { return identifier.replaceAll("A", REPLACE_A).replaceAll("\\$", REPLACE_$); }

      public static String decodeIdentifierFromXML(String identifier) {
      String res = identifier;
      int idx = res.indexOf(REPLACE_$);
      while (idx > 0) {
      int c = 0;
      for (int i = idx - 1; i >= 0; i--) {
      if (res.charAt == 'A')
      c++;
      else if (c % 2 == 0)

      { res = res.substring(0, idx) + "$" + res.substring(idx + 2); break; }

      }
      idx = res.indexOf(REPLACE_$, idx);
      }
      res = res.replaceAll(REPLACE_A, "A");
      return res;
      }
      }

      package com.thoughtworks.xstream.io.xml;

      import com.thoughtworks.xstream.converters.ErrorWriter;
      import com.thoughtworks.xstream.core.util.EncodeDecodeHelper;
      import com.thoughtworks.xstream.io.HierarchicalStreamReader;
      import org.dom4j.Document;
      import org.dom4j.Element;

      import java.util.LinkedList;

      public class Dom4JReader implements HierarchicalStreamReader {

      private Element currentElement;
      private LinkedList pointers = new LinkedList();

      public Dom4JReader(Element rootElement)

      { currentElement = rootElement; pointers.addLast(new Pointer()); }

      public Dom4JReader(Document document)

      { currentElement = document.getRootElement(); pointers.addLast(new Pointer()); }

      public String getNodeName()

      { return EncodeDecodeHelper.decodeIdentifierFromXML(currentElement.getName()); }

      public String getValue()

      { return currentElement.getText(); }

      public String getAttribute(String name)

      { return currentElement.attributeValue(name); }

      public Object peekUnderlyingNode()

      { return currentElement; }

      private class Pointer { public int v; }

      public boolean hasMoreChildren() {
      Pointer pointer = (Pointer) pointers.getLast();

      if (pointer.v < currentElement.elements().size()) { return true; } else { return false; }
      }

      public void moveUp() { currentElement = currentElement.getParent(); pointers.removeLast(); }

      public void moveDown() { Pointer pointer = (Pointer) pointers.getLast(); pointers.addLast(new Pointer()); currentElement = (Element) currentElement.elements().get(pointer.v); pointer.v++; }

      public void appendErrors(ErrorWriter errorWriter) { errorWriter.add("xpath", currentElement.getPath()); }

      }



      package com.thoughtworks.xstream.io.xml;

      import com.thoughtworks.xstream.converters.ErrorWriter;
      import com.thoughtworks.xstream.io.HierarchicalStreamReader;
      import org.w3c.dom.*;

      import java.util.ArrayList;
      import java.util.LinkedList;
      import java.util.List;

      public class DomReader implements HierarchicalStreamReader {

      private Element currentElement;
      private StringBuffer textBuffer;
      private NodeList childNodes;
      private LinkedList pointers = new LinkedList();
      private List childElements;

      public DomReader(Element rootElement) { textBuffer = new StringBuffer(180); pointers.addLast(new Pointer()); setCurrent(rootElement); }

      public DomReader(Document document) { textBuffer = new StringBuffer(180); pointers.addLast(new Pointer()); setCurrent(document.getDocumentElement()); }

      public String getNodeName() { return currentElement.getTagName(); }

      public String getValue() {
      NodeList childNodes = currentElement.getChildNodes();
      textBuffer.setLength(0);
      int length = childNodes.getLength();
      for (int i = 0; i < length; i++) {
      Node childNode = childNodes.item;
      if (childNode instanceof Text) { Text text = (Text) childNode; textBuffer.append(text.getData()); }
      }
      return textBuffer.toString();
      }

      public String getAttribute(String name) { Attr attribute = currentElement.getAttributeNode(name); return attribute == null ? null : attribute.getValue(); }

      public Object peekUnderlyingNode() { return currentElement; }

      private void setCurrent(Object currentElementObj) {
      this.currentElement = (Element) currentElementObj;
      childNodes = currentElement.getChildNodes();
      childElements = new ArrayList();
      for (int i = 0; i < childNodes.getLength(); i++) {
      Node node = childNodes.item;
      if (node instanceof Element)

      { childElements.add(node); }

      }
      }

      private class Pointer

      { public int v; }

      public boolean hasMoreChildren() {
      Pointer pointer = (Pointer) pointers.getLast();

      if (pointer.v < childElements.size())

      { return true; }

      else

      { return false; }

      }

      public void moveUp()

      { setCurrent(currentElement.getParentNode()); pointers.removeLast(); }

      public void moveDown()

      { Pointer pointer = (Pointer) pointers.getLast(); pointers.addLast(new Pointer()); setCurrent(childElements.get(pointer.v)); pointer.v++; }

      public void appendErrors(ErrorWriter errorWriter) {
      }
      }

      package com.thoughtworks.xstream.io.xml;
      import com.thoughtworks.xstream.converters.ErrorWriter;
      import com.thoughtworks.xstream.core.util.EncodeDecodeHelper;
      import com.thoughtworks.xstream.io.HierarchicalStreamReader;
      import com.thoughtworks.xstream.io.xml.xppdom.Xpp3Dom;
      import java.util.LinkedList;
      /**

      • @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
      • @version $Id: XppDomReader.java,v 1.2 2004/05/08 17:51:19 joe Exp $
        */
        public class XppDomReader implements HierarchicalStreamReader {
        private Xpp3Dom current;
        private LinkedList pointers = new LinkedList();
        public XppDomReader(Xpp3Dom xpp3Dom) { current = xpp3Dom; pointers.addLast(new Pointer()); }

        public String getNodeName()

        { return EncodeDecodeHelper.decodeIdentifierFromXML(current.getName()); }

        public String getValue()

        Unknown macro: { String text = null; try { text = current.getValue(); } catch (Exception e) { // do nothing. }
        return text == null ? "" : text;
        }
        public String getAttribute(String attributeName) {
        String text = null;
        try { text = current.getAttribute(attributeName); } catch (Exception e) { // do nothing. } return text; }

        public Object peekUnderlyingNode()

        { return current; }

        private class Pointer

        { public int v; }

        public boolean hasMoreChildren()

        Unknown macro: { Pointer pointer = (Pointer) pointers.getLast(); if (pointer.v < current.getChildCount()) { return true; } else { return false; } }

        public void moveUp()

        { current = current.getParent(); pointers.removeLast(); }

        public void moveDown()

        { Pointer pointer = (Pointer) pointers.getLast(); pointers.addLast(new Pointer()); current = current.getChild(pointer.v); pointer.v++; }

        public void appendErrors(ErrorWriter errorWriter) {}
        }

      package com.thoughtworks.xstream.io.xml;
      import com.thoughtworks.xstream.converters.ErrorWriter;
      import com.thoughtworks.xstream.core.util.EncodeDecodeHelper;
      import com.thoughtworks.xstream.core.util.IntQueue;
      import com.thoughtworks.xstream.core.util.StringStack;
      import com.thoughtworks.xstream.io.HierarchicalStreamReader;
      import com.thoughtworks.xstream.io.StreamException;
      import org.xmlpull.mxp1.MXParser;
      import org.xmlpull.v1.XmlPullParser;
      import org.xmlpull.v1.XmlPullParserException;
      import java.io.BufferedReader;
      import java.io.IOException;
      import java.io.Reader;
      public class XppReader implements HierarchicalStreamReader {
      private final XmlPullParser parser;
      private final StringStack elementStack = new StringStack(16);
      private final IntQueue lookaheadQueue = new IntQueue(4);
      public XppReader(Reader reader) {
      try

      { parser = createParser(); parser.setInput(new BufferedReader(reader)); moveDown(); }

      catch (XmlPullParserException e)

      { throw new StreamException(e); }
      }
      protected XmlPullParser createParser() { // WARNING, read comment in getValue() before switching // to a different parser. return new MXParser(); }
      public boolean hasMoreChildren() {
      while (true) {
      switch (lookahead()) { case XmlPullParser.START_TAG : return true; case XmlPullParser.END_TAG : case XmlPullParser.END_DOCUMENT : return false; default : continue; }
      }
      }
      private int lookahead() {
      try { int event = parser.next(); lookaheadQueue.write(event); return event; } catch (XmlPullParserException e) { throw new StreamException(e); }

      catch (IOException e)

      { throw new StreamException(e); }

      }
      private int next() {
      if (!lookaheadQueue.isEmpty())

      { return lookaheadQueue.read(); }

      else {
      try

      { return parser.next(); }

      catch (XmlPullParserException e)

      { throw new StreamException(e); } catch (IOException e) { throw new StreamException(e); }

      }
      }
      public void moveDown() {
      int currentDepth = elementStack.size();
      while (elementStack.size() <= currentDepth) {
      read();
      if (elementStack.size() < currentDepth)

      { throw new RuntimeException(); // sanity check }

      }
      }
      public void moveUp() {
      int currentDepth = elementStack.size();
      while (elementStack.size() >= currentDepth)

      { read(); }

      }
      public String getNodeName()

      { return elementStack.peek(); }

      public String getValue() {
      // MXP1 (pull parser) collapses all text into a single
      // text event. This allows us to only need to lookahead
      // one step. However if using a different pull parser
      // impl, you may need to look ahead further.
      if (lookahead() == XmlPullParser.TEXT)

      { String text = parser.getText(); return text == null ? "" : text; }

      else

      { return ""; }

      }
      public String getAttribute(String name)

      { return parser.getAttributeValue(null, name); }

      public Object peekUnderlyingNode()

      { throw new UnsupportedOperationException(); }

      private void read() {
      switch (next())

      { case XmlPullParser.START_TAG : elementStack.push(EncodeDecodeHelper.decodeIdentifierFromXML(parser.getName())); break; case XmlPullParser.END_TAG : case XmlPullParser.END_DOCUMENT : elementStack.pop(); break; }

      }
      public void appendErrors(ErrorWriter errorWriter)

      { errorWriter.add("line number", String.valueOf(parser.getLineNumber())); }

      }

      package com.thoughtworks.xstream.io.xml;
      import com.thoughtworks.xstream.core.util.EncodeDecodeHelper;
      import com.thoughtworks.xstream.core.util.QuickWriter;
      import com.thoughtworks.xstream.core.util.StringStack;
      import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
      import java.io.PrintWriter;
      import java.io.Writer;
      public class PrettyPrintWriter implements HierarchicalStreamWriter {
      private final QuickWriter writer;
      private final StringStack elementStack = new StringStack(16);
      private final char[] lineIndenter;
      private boolean tagInProgress;
      private int depth;
      private boolean readyForNewLine;
      private boolean tagIsEmpty;
      private static final char[] AMP =

      { '&', 'a', 'm', 'p', ';' }

      ;
      private static final char[] LT =

      { '&', 'l', 't', ';' }

      ;
      private static final char[] GT =

      { '&', 'g', 't', ';' }

      ;
      private static final char[] CLOSE =

      { '<', '/' }

      ;
      public PrettyPrintWriter(Writer writer, char[] lineIndenter)

      { this.writer = new QuickWriter(writer); this.lineIndenter = lineIndenter; }

      public PrettyPrintWriter(Writer writer, String lineIndenter)

      { this(writer, lineIndenter.toCharArray()); }

      public PrettyPrintWriter(PrintWriter writer) {
      this(writer, new char[]

      { ' ', ' ' }

      );
      }
      public PrettyPrintWriter(Writer writer)

      { this(new PrintWriter(writer)); }

      public void startNode(String name)

      { name = EncodeDecodeHelper.encodeIdentifier2XML(name); tagIsEmpty = false; finishTag(); writer.write('<'); writer.write(name); elementStack.push(name); tagInProgress = true; depth++; readyForNewLine = true; tagIsEmpty = true; }

      public void setValue(String text) {
      readyForNewLine = false;
      tagIsEmpty = false;
      finishTag();
      // Profiler said this was a bottleneck
      final char[] chars = text.toCharArray();
      final int length = chars.length;
      for (int i = 0; i < length; i++) {
      final char c = chars[i];
      switch (c)

      { case '&' : writer.write(AMP); break; case '<' : writer.write(LT); break; case '>' : writer.write(GT); break; default : writer.write(c); }

      }
      // end bottleneck
      }
      public void addAttribute(String key, String value)

      { writer.write(' '); writer.write(key); writer.write('='); writer.write('\"'); writer.write(value); writer.write('\"'); }

      public void endNode() {
      depth--;
      if (tagIsEmpty)

      { writer.write('/'); readyForNewLine = false; finishTag(); elementStack.popSilently(); }

      else

      { finishTag(); writer.write(CLOSE); writer.write(elementStack.pop()); writer.write('>'); }

      readyForNewLine = true;
      writer.flush();
      }
      private void finishTag() {
      if (tagInProgress)

      { writer.write('>'); }

      tagInProgress = false;
      if (readyForNewLine)

      { endOfLine(); }

      readyForNewLine = false;
      tagIsEmpty = false;
      }
      protected void endOfLine() {
      writer.write('\n');
      for (int i = 0; i < depth; i++)

      { writer.write(lineIndenter); }

      }
      }

        People

        • Assignee:
          Unassigned
          Reporter:
          Joe Walnes
        • Votes:
          0 Vote for this issue
          Watchers:
          0 Start watching this issue

          Dates

          • Created:
            Updated:
            Resolved: