I am writing code to unmarshal XML from a file. I don't know up front which schema the XML is based on so I try to unmarshal it with several schemas in the form of different Jaxb2Marshaller instances.
The method needs to:
Here is the current code:
private Object getObject(final byte[] data) throws MyException {
String lastErrorMessage = "";
for (final Jaxb2Marshaller marshaller : this.marshallers) {
try {
return marshaller.unmarshal(new StreamSource(new ByteArrayInputStream(data)));
} catch (final XmlMappingException e) {
LOGGER.warn("Invalid XML", e);
lastErrorMessage = e.getMessage();
}
}
throw new MyException(lastErrorMessage);
}
I feel this method does too many things at different levels of abstraction:
But I don't see a way to simplify it. The try-catch block is needed for every marshaller (because I should catch and ignore these XmlMappingExceptions except the last one). That block either returns a result object, or the lastErrorMessage, which is needed below the iteration to throw the MyException.
The only solution I can think of is to create some contrived Result class which contains either the result object or the error message but that feels cludgy. Any other insights?
I would like methods with a granularity like these:
private Object getObject(byte[] data) throws MyException {
Result result;
for (Jaxb2Marshaller marshaller : this.marshallers) {
result = getObject(marshaller, data);
}
return handleError(result);
}
private Result getObject(Jaxb2Marshaller marshaller, byte[] data) {
try {
return Result.value(marshaller.unmarshal(new StreamSource(new ByteArrayInputStream(data))));
} catch (final XmlMappingException e) {
LOGGER.warn("Invalid XML", e);
return Result.error(e.getMessage());
}
}
private Object handleError(Result result) {
if (result.isError()) {
throw new MyException(result.errroMessage);
}
else {
return result.value;
}
}
But the additional Result class is verbose and cludgy:
private class Result {
String errorMessage;
Object value;
static Result error(String errorMessage) {
Result result = new Result();
result.errorMessage = errorMessage;
return result;
}
static Result value(Object value) {
Result result = new Result();
result.value = value;
return result;
}
boolean isError() {
return errorMessage != null;
}
}
How about this?
public class MultiUnmarshaller {
private final List<Jaxb2Marshaller> marshallers;
private Object value;
private String error;
public MultiUnmarshaller(List<Jaxb2Marshaller> marshallers) {
this.marshallers = marshallers;
}
private void init() {
error = "No marshallers available";
value = null;
}
public Object getObject(byte[] data) throws MyException {
init();
Iterator<Jaxb2Marshaller> it = marshallers.iterator();
while(it.hasNext() && errorMessage != null) {
unmarshalObject(marshaller, data);
}
return produceResult();
}
private void unmarshalObject(Jaxb2Marshaller marshaller, byte[] data) {
try {
value = marshaller.unmarshal(new StreamSource(new ByteArrayInputStream(data)));
error = null;
} catch (final XmlMappingException e) {
LOGGER.warn("Invalid XML", e);
error = e.getMessage();
}
}
private Object produceResult() {
if (error == null) {
return value;
}
else {
throw new MyException(error);
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.