16
16
package no .digipost .signature .jaxb ;
17
17
18
18
import 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 ;
19
22
import org .w3c .dom .Document ;
20
- import org .xml .sax .InputSource ;
21
- import org .xml .sax .XMLReader ;
23
+ import org .w3c .dom .Node ;
22
24
23
- import javax .xml .XMLConstants ;
24
25
import javax .xml .bind .JAXBContext ;
25
- import javax .xml .bind .JAXBException ;
26
26
import javax .xml .bind .Marshaller ;
27
27
import javax .xml .bind .Unmarshaller ;
28
- import javax .xml .parsers .SAXParser ;
29
- import javax .xml .parsers .SAXParserFactory ;
30
28
import javax .xml .transform .Source ;
31
29
import javax .xml .transform .dom .DOMResult ;
32
- import javax .xml .transform .sax .SAXSource ;
33
- import javax .xml .validation .Schema ;
34
- import javax .xml .validation .SchemaFactory ;
35
30
36
31
import java .io .ByteArrayInputStream ;
37
32
import java .io .ByteArrayOutputStream ;
38
- import java .io .IOException ;
39
33
import java .io .InputStream ;
40
34
import java .io .OutputStream ;
41
- import java .io .UncheckedIOException ;
42
- import java .net .URL ;
43
- import java .util .Collection ;
44
- import java .util .Optional ;
45
35
import java .util .Set ;
46
- import java .util .stream .Stream ;
47
36
48
37
import 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 ;
51
39
52
40
/**
53
41
* @see JaxbMarshaller.ForResponsesOfAllApis
@@ -71,7 +59,7 @@ private static final class SingletonHolder {
71
59
}
72
60
73
61
public ForRequestsOfAllApis () {
74
- super (SignatureMarshalling . allApiRequestClasses ( ), SignatureApiSchemas . DIRECT_AND_PORTAL_API );
62
+ super (validateUsingSchemaResources ( SignatureApiSchemas . DIRECT_AND_PORTAL_API ), SignatureMarshalling . allApiRequestClasses () );
75
63
}
76
64
}
77
65
@@ -91,7 +79,7 @@ private static final class SingletonHolder {
91
79
}
92
80
93
81
public ForResponsesOfAllApis () {
94
- super (SignatureMarshalling .allApiResponseClasses ());
82
+ super (MarshallingCustomization . NO_CUSTOMIZATION , SignatureMarshalling .allApiResponseClasses ());
95
83
}
96
84
}
97
85
@@ -119,72 +107,42 @@ private static final class SingletonHolder {
119
107
}
120
108
121
109
public ForAllApis () {
122
- super (SignatureMarshalling . allApiClasses ( ), SignatureApiSchemas . DIRECT_AND_PORTAL_API );
110
+ super (validateUsingSchemaResources ( SignatureApiSchemas . DIRECT_AND_PORTAL_API ), SignatureMarshalling . allApiClasses () );
123
111
}
124
112
}
125
113
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 ;
146
117
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 ();
165
122
}
166
123
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 ()]));
174
126
}
175
127
176
- private final JAXBContext jaxbContext ;
177
- private final Optional <Schema > schema ;
128
+ public JaxbMarshaller (Class <?> ... classesToBeBound ) {
129
+ this (MarshallingCustomization .NO_CUSTOMIZATION , classesToBeBound );
130
+ }
178
131
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 );
182
134
}
183
135
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 );
186
143
}
187
144
145
+
188
146
public String marshalToString (Object object ) {
189
147
return marshalToResult (object , xml -> xml .toString (UTF_8 .name ()));
190
148
}
@@ -228,26 +186,30 @@ private interface ThrowingBiConsumer<T, S> {
228
186
private <T > void doWithMarshaller (T object , ThrowingBiConsumer <? super T , ? super Marshaller > operation ) {
229
187
try {
230
188
Marshaller marshaller = jaxbContext .createMarshaller ();
231
- schema . ifPresent (marshaller :: setSchema );
189
+ marshallingCustomization . customize (marshaller );
232
190
operation .accept (object , marshaller );
233
191
} catch (Exception e ) {
234
192
throw SignatureMarshalException .failedMarshal (object , e );
235
193
}
236
194
}
237
195
238
-
239
196
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 );
241
199
}
242
200
243
201
public <T > T unmarshal (byte [] bytes , Class <T > type ) {
244
202
return unmarshal (new ByteArrayInputStream (bytes ), type );
245
203
}
246
204
205
+ public <T > T unmarshal (Node node , Class <T > type ) {
206
+ return unmarshal (unmarshaller -> unmarshaller .unmarshal (node ), type );
207
+ }
208
+
247
209
private <T > T unmarshal (ThrowingFunction <? super Unmarshaller , ?> operation , Class <T > type ) {
248
210
try {
249
211
Unmarshaller unmarshaller = jaxbContext .createUnmarshaller ();
250
- schema . ifPresent (unmarshaller :: setSchema );
212
+ marshallingCustomization . customize (unmarshaller );
251
213
return type .cast (operation .apply (unmarshaller ));
252
214
} catch (Exception e ) {
253
215
throw SignatureMarshalException .failedUnmarshal (type , e );
0 commit comments