Reputation: 10841
I'm trying to send java bean instances over a network stream. I want to marshal/unmarshal java instances with JAXB
and a normal OutputStream
to push it over the network.
The servers wait at the unmarshal point but the client is already alot further.
Server:
inputStream = new BufferedInputStream(this.socket.getInputStream());
outputStream = new BufferedOutputStream(this.socket.getOutputStream());
JAXBContext requestContext = JAXBContext.newInstance(this.requestClass);
Unmarshaller unmarshaller = requestContext.createUnmarshaller();
@SuppressWarnings("unchecked")
K request = (K) unmarshaller.unmarshal(inputStream); //blocks here
respond();
Client:
JAXBContext messageContext = JAXBContext.newInstance(message.getClass());
Marshaller marshaller = messageContext.createMarshaller();
out = new BufferedOutputStream(socket.getOutputStream());
marshaller.marshal(message, out);
out.flush();
waitForResponse();// blocks here
EDIT: I switched to a normal output stream but it still blocks. Do I have to send some special signal to tell JAXB to stop unmarshalling? If I close the client output stream the message arrives at the server side.
Upvotes: 4
Views: 3264
Reputation: 10841
I switched to XMLEventWriter
and XMLEventWriter
and it works. I've got the feeling XMLStreamReader
is buggy. It gets stuck on some skipSpaces()
method. The code of XMLStreamReader
looks as if it should return as soon as a end of document appears.
Upvotes: 3
Reputation: 80623
It would seem that the unmarshaller is choking on socket output stream semantics. My guess would be that it is expecting the stream to be terminated by signalling -1 for the available length, and blocks trying to read forever when it gets 0 instead. Though it may seem hackish, you can get around this problem by using intermediate reader/writers.
Here is an example, based on your code, using intermediary string reader/writer:
Server:
final BufferedReader socketReader = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
final StringReader dataReader = new StringReader(socketReader.readLine());
JAXBContext requestContext = JAXBContext.newInstance(this.requestClass);
Unmarshaller unmarshaller = requestContext.createUnmarshaller();
@SuppressWarnings("unchecked")
K request = (K) unmarshaller.unmarshal(dataReader);
respond();
Client:
JAXBContext messageContext = JAXBContext.newInstance(message.getClass());
Marshaller marshaller = messageContext.createMarshaller();
final StringWriter dataWriter = new StringWriter();
marshaller.marshal(message, dataWriter);
out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
out.write(dataWriter.toString());
out.newLine();
out.flush();
waitForResponse();
Upvotes: 1
Reputation: 53694
unfortunately, i think the xml parser waits for end of stream before finishing (it doesn't give up just because it has received the "end" of the xml).
one option would be to put some stream wrapper on top of the socket stream which returns -1 after all the xml data has been read. however, figuring out when you have reached that point is a non-trivial situation.
another option would be to create your own XMLEventReader which wraps a delegate XMLEventReader and ends after the closing xml event is received.
This is another solution (custom "end of stream" marks).
Upvotes: 0