• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.fasterxml.jackson.databind.ext;
2 
3 import java.io.StringReader;
4 
5 import javax.xml.XMLConstants;
6 import javax.xml.parsers.DocumentBuilder;
7 import javax.xml.parsers.DocumentBuilderFactory;
8 import javax.xml.parsers.ParserConfigurationException;
9 
10 import org.w3c.dom.Document;
11 import org.w3c.dom.Node;
12 import org.xml.sax.InputSource;
13 
14 import com.fasterxml.jackson.databind.DeserializationContext;
15 import com.fasterxml.jackson.databind.deser.std.FromStringDeserializer;
16 
17 /**
18  * Base for serializers that allows parsing DOM Documents from JSON Strings.
19  * Nominal type can be either {@link org.w3c.dom.Node} or
20  * {@link org.w3c.dom.Document}.
21  */
22 public abstract class DOMDeserializer<T> extends FromStringDeserializer<T>
23 {
24     private static final long serialVersionUID = 1L;
25 
26     private final static DocumentBuilderFactory DEFAULT_PARSER_FACTORY;
27     static {
28         DocumentBuilderFactory parserFactory = DocumentBuilderFactory.newInstance();
29         // yup, only cave men do XML without recognizing namespaces...
30         parserFactory.setNamespaceAware(true);
31         // [databind#1279]: make sure external entities NOT expanded by default
32         parserFactory.setExpandEntityReferences(false);
33         // ... and in general, aim for "safety"
34         try {
parserFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true)35             parserFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
36         } catch(ParserConfigurationException pce) {
37             // not much point to do anything; could log but...
38         } catch (Error e) {
39             // 14-Jul-2016, tatu: Not sure how or why, but during code coverage runs
40             //   (via Cobertura) we get `java.lang.AbstractMethodError` so... ignore that too
41         }
42 
43         // [databind#2589] add two more settings just in case
44         try {
45             parserFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
46         } catch (Throwable t) { } // as per previous one, nothing much to do
47         try {
48             parserFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
49         } catch (Throwable t) { } // as per previous one, nothing much to do
50         DEFAULT_PARSER_FACTORY = parserFactory;
51     }
52 
DOMDeserializer(Class<T> cls)53     protected DOMDeserializer(Class<T> cls) { super(cls); }
54 
55     @Override
_deserialize(String value, DeserializationContext ctxt)56     public abstract T _deserialize(String value, DeserializationContext ctxt);
57 
parse(String value)58     protected final Document parse(String value) throws IllegalArgumentException {
59         try {
60             return documentBuilder().parse(new InputSource(new StringReader(value)));
61         } catch (Exception e) {
62             throw new IllegalArgumentException("Failed to parse JSON String as XML: "+e.getMessage(), e);
63         }
64     }
65 
66     /**
67      * Overridable factory method used to create {@link DocumentBuilder} for parsing
68      * XML as DOM.
69      *
70      * @since 2.7.6
71      */
documentBuilder()72     protected DocumentBuilder documentBuilder() throws ParserConfigurationException {
73         return DEFAULT_PARSER_FACTORY.newDocumentBuilder();
74     }
75 
76     /*
77     /**********************************************************
78     /* Concrete deserializers
79     /**********************************************************
80      */
81 
82     public static class NodeDeserializer extends DOMDeserializer<Node> {
83         private static final long serialVersionUID = 1L;
NodeDeserializer()84         public NodeDeserializer() { super(Node.class); }
85         @Override
_deserialize(String value, DeserializationContext ctxt)86         public Node _deserialize(String value, DeserializationContext ctxt) throws IllegalArgumentException {
87             return parse(value);
88         }
89     }
90 
91     public static class DocumentDeserializer extends DOMDeserializer<Document> {
92         private static final long serialVersionUID = 1L;
DocumentDeserializer()93         public DocumentDeserializer() { super(Document.class); }
94         @Override
_deserialize(String value, DeserializationContext ctxt)95         public Document _deserialize(String value, DeserializationContext ctxt) throws IllegalArgumentException {
96             return parse(value);
97         }
98     }
99 }
100