Franz Kafka
Franz Kafka

Reputation: 10841

JAXB through sockets and streams - reader blocks

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

Answers (3)

Franz Kafka
Franz Kafka

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

Perception
Perception

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

jtahlborn
jtahlborn

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

Related Questions