简体   繁体   中英

How can I simplify this parsing method?

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:

  1. attempt to unmarshal the XML with each marshaller
  2. If this succeeds, return the resulting object
  3. If it fails, try the next marshaller
  4. If all marshallers fail, throw an exception with the last error message

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:

  • iterate over marshallers
  • apply a marshaller
  • return result
  • catch exceptions
  • throw exception

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM