在 JAXB 反序列化/序列化期间获取进度信息

Posted

技术标签:

【中文标题】在 JAXB 反序列化/序列化期间获取进度信息【英文标题】:Get progress information during JAXB de-/serialization 【发布时间】:2017-08-14 11:16:07 【问题描述】:

有没有办法在 JAXB Marshaller 和 Unmarshaller 上注册一些进度监视器? 我想在数据反序列化/序列化时在我的 GUI 中显示一些进度信息。

我看到你可以设置一个Unmarshaller.ListenerMarshaller.Listener,它们有一个“之前”和“之后”的方法。不过,我没有看到任何直接的方法来获取要序列化的元素总数。

我显然需要它来计算一些“完成百分比”信息。

【问题讨论】:

【参考方案1】:

解组前解析可以吗?

如果是这样,假设您有一个对象列表,您可以执行类似...

    final String tagName = *** name of tag you are counting ***;
    InputStream in = *** stream of your xml ***;

    SAXParserFactory spf = SAXParserFactory.newInstance();
    SAXParser saxParser = spf.newSAXParser();
    final AtomicInteger counter = new AtomicInteger();
    saxParser.parse(in, new DefaultHandler() 
        @Override
        public void startElement (String uri, String localName, String qName, Attributes attributes) 
            if (localName.equals(tagName))
                counter.incrementAndGet();
        
    );

【讨论】:

这可能是一种解决方法。我的 tagName 在 xml 树中不是唯一的怎么办? 然后检查一组名称而不是单个名称。 编组是否类似?【参考方案2】:

通过利用 InputStream 来做一个更底层的方法是一个可接受的解决方案吗?

例如

import java.io.IOException;
import java.io.InputStream;
import java.util.function.DoubleConsumer;

public class InputStreamWithProgressDecorator extends InputStream 
    /** Input stream to be decorated */ private final InputStream inputStream;
    /** Amount of byte read */ private long position = 0L;
    /** File size */ private final long length;
    /** Mark */ private int mark = 0;
    /** Consumer of the progress */ private final DoubleConsumer callBack;
    
    public InputStreamWithProgressDecorator(final InputStream is, final long l, final DoubleConsumer cb) 
        inputStream = is;
        length = l;
        callBack = cb;
    

    private void setPosition(final long fp) 
        position = fp;
        callBack.accept(getProgress());
    

    public double getProgress() 
        return length == 0L ? 100d : ((double) position) * 100d / ((double) length);
    

    public long getPosition() 
        return position;
    

    @Override
    public int read(byte[] b) throws IOException 
        final int rc = inputStream.read(b);
        setPosition(position + rc);
        return rc;
    

    @Override
    public int read(byte[] b, int off, int len) throws IOException 
        final int rc = inputStream.read(b, off, len);
        setPosition(position + rc);
        return rc;
    

    @Override
    public byte[] readAllBytes() throws IOException 
        final byte[] result = inputStream.readAllBytes();
        setPosition(position + result.length);
        return result;
    

    @Override
    public byte[] readNBytes(int len) throws IOException 
        final byte[] result = inputStream.readNBytes(len);
        setPosition(position + result.length);
        return result;
    

    @Override
    public int readNBytes(byte[] b, int off, int len) throws IOException 
        final int rc = inputStream.readNBytes(b, off, len);
        setPosition(position + rc);
        return rc;
    

    @Override
    public long skip(long n) throws IOException 
        final long rc = inputStream.skip(n);
        setPosition(position + rc);
        return rc;
    

    @Override
    public int available() throws IOException 
        return inputStream.available();
    

    @Override
    public void close() throws IOException 
        inputStream.close();
    

    @Override
    public synchronized void mark(int readlimit) 
        inputStream.mark(readlimit);
        mark = readlimit;
    

    @Override
    public synchronized void reset() throws IOException 
        inputStream.reset();
        setPosition(mark);
    

    @Override
    public boolean markSupported() 
        return inputStream.markSupported();
    

    @Override
    public int read() throws IOException 
        final int c = inputStream.read();
        setPosition(position + 1);
        return c;
    

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.function.DoubleConsumer;

public class Demo1 

    public static void main(String[] args) throws IOException 
        final File file = new File(args[0]);
        final DoubleConsumer callBack = p -> System.out.printf("%.0f%%\n", p);
        try (final FileInputStream fis = new FileInputStream(file); final InputStreamWithProgressDecorator is = new InputStreamWithProgressDecorator(fis, file.length(), callBack)) 
            // Simulating JAXB unmarshaller reads
            byte[] buffer = is.readNBytes(1024);
            while (buffer.length != 0) buffer = is.readNBytes(1024); 
        
    

或者,如果您有一个带有单独线程方法的 FileInputStream:

public class FileInputStreamReadProgressThread extends Thread implements UncaughtExceptionHandler 
    /** Input stream */ private final FileInputStream fileInputStream;
    /** File size */ private final long length;
    /** Read progress in percents */ private double progress = 0d;
    /** Exception from thread */ private Throwable exception = null;
    /** Consumer of the progress */ private final DoubleConsumer callBack;

    public FileInputStreamReadProgressThread(final FileInputStream fis, final long l, final DoubleConsumer cb) 
        fileInputStream = fis;
        length = l;
        callBack = cb;
        setUncaughtExceptionHandler(this);
        setName(getClass().getSimpleName());
    

    public double getProgress()  return progress; 
    public Throwable getException()  return exception; 
    @Override public void uncaughtException(final Thread t, final Throwable e)  exception = e; 
    
    @Override
    public void run() 
        try 
            long position = -1L;
            final FileChannel channel = fileInputStream.getChannel();
            while (!isInterrupted() && channel.isOpen() && position < length) 
                position = channel.position();
                progress = length == 0L ? 100d : ((double)position) * 100d / ((double)length);
                callBack.accept(progress);
                sleep(100L);
             
         catch (final IOException e) 
            exception = e;
         catch (final InterruptedException e) 
            // Do nothing
        
    

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.Channels;
import java.util.function.DoubleConsumer;

public class Demo2 

    public static void main(String[] args) throws IOException 
        final File file = new File(args[0]);
        final DoubleConsumer callBack = p -> System.out.printf("%.0f%%\n", p);
        try (final FileInputStream fis = new FileInputStream(file); final InputStream is = Channels.newInputStream(fis.getChannel())) 
            final FileInputStreamReadProgressThread readProgressThread = new FileInputStreamReadProgressThread(fis, file.length(), callBack);
            readProgressThread.start();
            // Simulating JAXB unmarshaller reads
            is.readAllBytes();
        
    

【讨论】:

以上是关于在 JAXB 反序列化/序列化期间获取进度信息的主要内容,如果未能解决你的问题,请参考以下文章

JAXB2序列化XML

如何自定义 SpringWebFlux WebClient xml+rss JAXB 反序列化?

测试Hessian反序反序列化 客户端少字段和多字段时能否成功

2:如何反序迭代一个序列(字符串,列表,元组)

C#反序列化Json字符串

在 Spring Boot 应用程序中从缓存中获取期间使用 @AutoValue 注释反序列化类