Java tutorial
/* * Copyright 2013 Gordon Burgett and individual contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.xflatdb.xflat.convert.converters; import java.beans.XMLDecoder; import java.beans.XMLEncoder; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.JDOMException; import org.jdom2.input.SAXBuilder; import org.jdom2.output.XMLOutputter; import org.xflatdb.xflat.convert.ConversionException; import org.xflatdb.xflat.convert.ConversionNotSupportedException; import org.xflatdb.xflat.convert.ConversionService; import org.xflatdb.xflat.convert.Converter; import org.xflatdb.xflat.convert.PojoConverter; /** * This PojoConverter maps Java beans to XML using {@link java.beans.XMLEncoder}. * @author Gordon */ public class JavaBeansPojoConverter implements PojoConverter { @Override public ConversionService extend(ConversionService service) { return new JavaBeansConversionService(service); } private static class JavaBeansConversionService implements ConversionService { ConversionService base; public JavaBeansConversionService(ConversionService base) { this.base = base; } @Override public boolean canConvert(Class<?> source, Class<?> target) { if (!base.canConvert(source, target)) { if (Element.class.equals(target)) makeConverters(source); else if (Element.class.equals(source)) { makeConverters(target); } else { //can't convert return false; } } //else the base can convert return true; } @Override public <T> T convert(Object source, Class<T> target) throws ConversionException { try { return base.convert(source, target); } catch (ConversionNotSupportedException ex) { if (source == null) { throw ex; } //the base class does not support the conversion - try to make converters if (Element.class.equals(target)) makeConverters(source.getClass()); else if (Element.class.equals(source.getClass())) { makeConverters(target); } else { //can't convert throw ex; } //try again now that we successfully made converters return base.convert(source, target); } } @Override public <S, T> void addConverter(Class<S> sourceType, Class<T> targetType, Converter<? super S, ? extends T> converter) { base.addConverter(sourceType, targetType, converter); } @Override public void removeConverter(Class<?> sourceType, Class<?> targetType) { base.removeConverter(sourceType, targetType); } private <T> void makeConverters(Class<T> clazz) { base.addConverter(clazz, Element.class, XMLEncoderConverter); base.addConverter(Element.class, clazz, getDecoder(clazz)); } } private static Converter<Object, Element> XMLEncoderConverter = new Converter<Object, Element>() { @Override public Element convert(Object source) throws ConversionException { byte[] bytes; try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { try (XMLEncoder encoder = new XMLEncoder(os)) { encoder.writeObject(source); } bytes = os.toByteArray(); } catch (IOException ex) { throw new ConversionException("Error converting object of class " + source.getClass(), ex); } try (ByteArrayInputStream is = new ByteArrayInputStream(bytes)) { Document doc = new SAXBuilder().build(is); return doc.getRootElement().getChild("object").detach(); } catch (JDOMException | IOException ex) { throw new ConversionException("Error converting object of class " + source.getClass(), ex); } } }; private static <U> Converter<Element, U> getDecoder(Class<U> clazz) { return new Converter<Element, U>() { final String version = System.getProperty("java.version"); @Override public U convert(Element source) throws ConversionException { byte[] bytes; try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { Document doc = new Document(); doc.setRootElement(new Element("java").setAttribute("version", version).setAttribute("class", "java.beans.XMLDecoder")); doc.getRootElement().addContent(source.detach()); XMLOutputter outputter = new XMLOutputter(); outputter.output(doc, os); bytes = os.toByteArray(); } catch (IOException ex) { throw new ConversionException("Error reading object of class " + source.getClass(), ex); } try (ByteArrayInputStream is = new ByteArrayInputStream(bytes)) { try (XMLDecoder decoder = new XMLDecoder(is)) { return (U) decoder.readObject(); } } catch (IOException ex) { throw new ConversionException("Error reading object of class " + source.getClass(), ex); } } }; } }