1616package no .digipost .signature .jaxb ;
1717
1818import no .digipost .signature .xsd .SignatureApiSchemas ;
19+ import no .digipost .xml .bind .MarshallingCustomization ;
20+ import no .digipost .xml .parsers .SaxParserProvider ;
21+ import no .digipost .xml .transform .sax .SaxInputSources ;
1922import org .w3c .dom .Document ;
20- import org .xml .sax .InputSource ;
21- import org .xml .sax .XMLReader ;
23+ import org .w3c .dom .Node ;
2224
23- import javax .xml .XMLConstants ;
2425import javax .xml .bind .JAXBContext ;
25- import javax .xml .bind .JAXBException ;
2626import javax .xml .bind .Marshaller ;
2727import javax .xml .bind .Unmarshaller ;
28- import javax .xml .parsers .SAXParser ;
29- import javax .xml .parsers .SAXParserFactory ;
3028import javax .xml .transform .Source ;
3129import javax .xml .transform .dom .DOMResult ;
32- import javax .xml .transform .sax .SAXSource ;
33- import javax .xml .validation .Schema ;
34- import javax .xml .validation .SchemaFactory ;
3530
3631import java .io .ByteArrayInputStream ;
3732import java .io .ByteArrayOutputStream ;
38- import java .io .IOException ;
3933import java .io .InputStream ;
4034import java .io .OutputStream ;
41- import java .io .UncheckedIOException ;
42- import java .net .URL ;
43- import java .util .Collection ;
44- import java .util .Optional ;
4535import java .util .Set ;
46- import java .util .stream .Stream ;
4736
4837import static java .nio .charset .StandardCharsets .UTF_8 ;
49- import static java .util .Objects .requireNonNull ;
50- import static java .util .stream .Collectors .joining ;
38+ import static no .digipost .xml .bind .MarshallingCustomization .validateUsingSchemaResources ;
5139
5240/**
5341 * @see JaxbMarshaller.ForResponsesOfAllApis
@@ -71,7 +59,7 @@ private static final class SingletonHolder {
7159 }
7260
7361 public ForRequestsOfAllApis () {
74- super (SignatureMarshalling . allApiRequestClasses ( ), SignatureApiSchemas . DIRECT_AND_PORTAL_API );
62+ super (validateUsingSchemaResources ( SignatureApiSchemas . DIRECT_AND_PORTAL_API ), SignatureMarshalling . allApiRequestClasses () );
7563 }
7664 }
7765
@@ -91,7 +79,7 @@ private static final class SingletonHolder {
9179 }
9280
9381 public ForResponsesOfAllApis () {
94- super (SignatureMarshalling .allApiResponseClasses ());
82+ super (MarshallingCustomization . NO_CUSTOMIZATION , SignatureMarshalling .allApiResponseClasses ());
9583 }
9684 }
9785
@@ -119,72 +107,42 @@ private static final class SingletonHolder {
119107 }
120108
121109 public ForAllApis () {
122- super (SignatureMarshalling . allApiClasses ( ), SignatureApiSchemas . DIRECT_AND_PORTAL_API );
110+ super (validateUsingSchemaResources ( SignatureApiSchemas . DIRECT_AND_PORTAL_API ), SignatureMarshalling . allApiClasses () );
123111 }
124112 }
125113
126- private static InputSource createInputSource (String resource ) {
127- URL resourceUrl = requireNonNull (JaxbMarshaller .class .getResource (resource ), resource );
128- try (InputStream inputStream = resourceUrl .openStream ()) {
129- ByteArrayOutputStream outputStream = new ByteArrayOutputStream ();
130-
131- final int bufLen = 1024 ;
132- byte [] buf = new byte [bufLen ];
133- int readLen ;
134- while ((readLen = inputStream .read (buf , 0 , bufLen )) != -1 )
135- outputStream .write (buf , 0 , readLen );
136-
137- InputSource source = new InputSource (new ByteArrayInputStream (outputStream .toByteArray ()));
138- source .setSystemId (resourceUrl .toString ());
139- return source ;
140- } catch (IOException e ) {
141- throw new UncheckedIOException (
142- "Unable to resolve " + resource + " from " + resourceUrl + ", " +
143- "because " + e .getClass ().getSimpleName () + " '" + e .getMessage () + "'" , e );
144- }
145- }
114+ private final JAXBContext jaxbContext ;
115+ private final MarshallingCustomization marshallingCustomization ;
116+ private final SaxParserProvider saxParserProvider ;
146117
147- private static Schema createSchema (Collection <String > resources ) {
148- try {
149- SAXParserFactory parserFactory = SAXParserFactory .newInstance ();
150- parserFactory .setNamespaceAware (true );
151- parserFactory .setFeature ("http://xml.org/sax/features/namespace-prefixes" , true );
152-
153- SAXParser saxParser = parserFactory .newSAXParser ();
154- XMLReader xmlReader = saxParser .getXMLReader ();
155- Source [] schemaSources = resources .stream ()
156- .map (resource -> new SAXSource (xmlReader , createInputSource (resource )))
157- .toArray (Source []::new );
158-
159- SchemaFactory schemaFactory = SchemaFactory .newInstance (XMLConstants .W3C_XML_SCHEMA_NS_URI );
160- Schema schema = schemaFactory .newSchema (schemaSources );
161- return schema ;
162- } catch (Exception e ) {
163- throw new RuntimeException ("Could not create schema from resources [" + String .join (", " , resources ) + "]" , e );
164- }
118+ public JaxbMarshaller (MarshallingCustomization marshallingCustomization , Class <?> ... classesToBeBound ) {
119+ this .jaxbContext = JaxbUtils .initContext (classesToBeBound );
120+ this .marshallingCustomization = marshallingCustomization ;
121+ this .saxParserProvider = SaxParserProvider .createSecuredProvider ();
165122 }
166123
167- private static JAXBContext initContext (Collection <Class <?>> classes ) {
168- Class <?>[] classesToBeBound = classes .toArray (new Class [classes .size ()]);
169- try {
170- return JAXBContext .newInstance (classesToBeBound );
171- } catch (JAXBException e ) {
172- throw new RuntimeException ("Could not create JAXBContext for classes [" + Stream .of (classesToBeBound ).map (Class ::getSimpleName ).collect (joining ("," )) + "]" , e );
173- }
124+ public JaxbMarshaller (MarshallingCustomization marshallingCustomization , Set <Class <?>> classesToBeBound ) {
125+ this (marshallingCustomization , classesToBeBound .toArray (new Class [classesToBeBound .size ()]));
174126 }
175127
176- private final JAXBContext jaxbContext ;
177- private final Optional <Schema > schema ;
128+ public JaxbMarshaller (Class <?> ... classesToBeBound ) {
129+ this (MarshallingCustomization .NO_CUSTOMIZATION , classesToBeBound );
130+ }
178131
179- public JaxbMarshaller (Set <Class <?>> classes , Set <String > schemaResources ) {
180- this .jaxbContext = initContext (classes );
181- this .schema = Optional .ofNullable (schemaResources ).filter (s -> !s .isEmpty ()).map (JaxbMarshaller ::createSchema );
132+ public JaxbMarshaller (Set <Class <?>> classesToBeBound ) {
133+ this (MarshallingCustomization .NO_CUSTOMIZATION , classesToBeBound );
182134 }
183135
184- public JaxbMarshaller (Set <Class <?>> classes ) {
185- this (classes , null );
136+ /**
137+ * @deprecated Use {@link #JaxbMarshaller(MarshallingCustomization, Set)} with
138+ * {@link MarshallingCustomization#validateUsingSchemaResources(Set)}
139+ */
140+ @ Deprecated
141+ public JaxbMarshaller (Set <Class <?>> classesToBeBound , Set <String > schemaResources ) {
142+ this (MarshallingCustomization .validateUsingSchemaResources (schemaResources ), classesToBeBound );
186143 }
187144
145+
188146 public String marshalToString (Object object ) {
189147 return marshalToResult (object , xml -> xml .toString (UTF_8 .name ()));
190148 }
@@ -228,26 +186,30 @@ private interface ThrowingBiConsumer<T, S> {
228186 private <T > void doWithMarshaller (T object , ThrowingBiConsumer <? super T , ? super Marshaller > operation ) {
229187 try {
230188 Marshaller marshaller = jaxbContext .createMarshaller ();
231- schema . ifPresent (marshaller :: setSchema );
189+ marshallingCustomization . customize (marshaller );
232190 operation .accept (object , marshaller );
233191 } catch (Exception e ) {
234192 throw SignatureMarshalException .failedMarshal (object , e );
235193 }
236194 }
237195
238-
239196 public <T > T unmarshal (InputStream inputStream , Class <T > type ) {
240- return unmarshal (unmarshaller -> unmarshaller .unmarshal (inputStream ), type );
197+ Source xmlSource = saxParserProvider .createSource (SaxInputSources .fromInputStreamPreventClose (inputStream ));
198+ return unmarshal (unmarshaller -> unmarshaller .unmarshal (xmlSource ), type );
241199 }
242200
243201 public <T > T unmarshal (byte [] bytes , Class <T > type ) {
244202 return unmarshal (new ByteArrayInputStream (bytes ), type );
245203 }
246204
205+ public <T > T unmarshal (Node node , Class <T > type ) {
206+ return unmarshal (unmarshaller -> unmarshaller .unmarshal (node ), type );
207+ }
208+
247209 private <T > T unmarshal (ThrowingFunction <? super Unmarshaller , ?> operation , Class <T > type ) {
248210 try {
249211 Unmarshaller unmarshaller = jaxbContext .createUnmarshaller ();
250- schema . ifPresent (unmarshaller :: setSchema );
212+ marshallingCustomization . customize (unmarshaller );
251213 return type .cast (operation .apply (unmarshaller ));
252214 } catch (Exception e ) {
253215 throw SignatureMarshalException .failedUnmarshal (type , e );
0 commit comments