001    
002    /*
003     * Copyright (C) 2011 Archie L. Cobbs. All rights reserved.
004     *
005     * $Id: IdMappingMarshaller.java 292 2012-02-19 21:14:45Z archie.cobbs $
006     */
007    
008    package org.dellroad.stuff.jibx;
009    
010    import java.io.IOException;
011    import java.util.concurrent.Callable;
012    
013    import javax.xml.transform.Result;
014    import javax.xml.transform.Source;
015    
016    import org.dellroad.stuff.java.IdGenerator;
017    import org.springframework.beans.factory.InitializingBean;
018    import org.springframework.oxm.Marshaller;
019    import org.springframework.oxm.Unmarshaller;
020    import org.springframework.oxm.jibx.JibxMarshaller;
021    
022    /**
023     * Wrapper for Spring's {@link JibxMarshaller} that performs marshalling and unmarshalling operations
024     * within an invocation of {@link IdGenerator#run IdGenerator.run()}. Simply set your
025     * normal {@link JibxMarshaller} to the {@linkplain #setJibxMarshaller jibxMarshaller}
026     * property and use this class in its place.
027     *
028     * <p>
029     * This is required when marshalling with JiBX mappings that utilize {@link IdMapper}.
030     *
031     * @see IdMapper
032     */
033    public class IdMappingMarshaller implements Marshaller, Unmarshaller, InitializingBean {
034    
035        private JibxMarshaller jibxMarshaller;
036    
037        /**
038         * Configure the nested {@link JibxMarshaller}. Required property.
039         */
040        public void setJibxMarshaller(JibxMarshaller jibxMarshaller) {
041            this.jibxMarshaller = jibxMarshaller;
042        }
043    
044        @Override
045        public void afterPropertiesSet() throws Exception {
046            if (this.jibxMarshaller == null)
047                throw new Exception("null jibxMarshaller");
048        }
049    
050        /**
051         * Invokdes {@link JibxMarshaller#marshal JibxMarshaller.marshal()} on the configured
052         * {@link JibxMarshaller} within an invocation of {@link IdGenerator#run(Callable) IdGenerator.run()}.
053         */
054        @Override
055        public void marshal(final Object graph, final Result result) throws IOException {
056            try {
057                IdGenerator.run(new Callable<Void>() {
058                    @Override
059                    public Void call() throws Exception {
060                        IdMappingMarshaller.this.jibxMarshaller.marshal(graph, result);
061                        return null;
062                    }
063                });
064            } catch (Exception e) {
065                this.unwrapException(e);
066            }
067        }
068    
069        /**
070         * Invokdes {@link JibxMarshaller#unmarshal JibxMarshaller.unmarshal()} on the configured
071         * {@link JibxMarshaller} within an invocation of {@link IdGenerator#run(Callable) IdGenerator.run()}.
072         */
073        @Override
074        public Object unmarshal(final Source source) throws IOException {
075            try {
076                return IdGenerator.run(new Callable<Object>() {
077                    @Override
078                    public Object call() throws Exception {
079                        return IdMappingMarshaller.this.jibxMarshaller.unmarshal(source);
080                    }
081                });
082            } catch (Exception e) {
083                this.unwrapException(e);
084                return null;                // never reached
085            }
086        }
087    
088        @Override
089        public boolean supports(Class<?> type) {
090            return this.jibxMarshaller.supports(type);
091        }
092    
093        private void unwrapException(Exception e) throws IOException {
094            if (e instanceof IOException)
095                throw (IOException)e.getCause();
096            if (e instanceof RuntimeException)
097                throw (RuntimeException)e;
098            throw new RuntimeException(e);
099        }
100    }
101