All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nuiton.io.xpp3.AbstractXpp3Reader Maven / Gradle / Ivy

The newest version!
/*
 * #%L
 * Maven helper plugin
 * 
 * $Id: AbstractXpp3Reader.java 814 2011-05-10 22:07:16Z tchemit $
 * $HeadURL: http://svn.nuiton.org/svn/maven-helper-plugin/tags/maven-helper-plugin-1.3/src/main/java/org/nuiton/io/xpp3/AbstractXpp3Reader.java $
 * %%
 * Copyright (C) 2009 - 2010 Tony Chemit, CodeLutin
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as 
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public 
 * License along with this program.  If not, see
 * .
 * #L%
 */

package org.nuiton.io.xpp3;

import org.codehaus.plexus.util.xml.pull.MXParser;
import org.codehaus.plexus.util.xml.pull.XmlPullParser;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;

import java.beans.IntrospectionException;
import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Array;
import java.util.*;
import java.util.Map.Entry;

/**
 * An abstract xpp3Reader based on {@link PropertyMapper} to set properties of
 * the objects to build.
 * 

* To implements a new parser, just implements method {@link #initMappers()} to * see authorized mapping from tag to pojo properties. *

* The logic of setting properties from xml (tag and attributes) is done in *

*

    *
  • {@link #read(String, Class, XmlPullParser, boolean)}
  • *
  • {@link #readArray(String, String, Class, XmlPullParser, boolean)}
  • *
*

* The default implementation is to map tag text to a pojo's property. *

* If you want to do something more complex, override these methods. * * @author tchemit * @param the type of object to be build by the reader * @see PropertyMapper * @see Xpp3Reader * @since 1.0.0 */ public abstract class AbstractXpp3Reader implements Xpp3Reader { /** * If set the parser will be loaded with all single characters * from the XHTML specification. * The entities used: *

    *
  • http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent
  • *
  • http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent
  • *
  • http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent
  • *
*/ protected boolean addDefaultEntities = true; /** the type of the object to produce from the xml streams. */ protected final Class type; /** the root tag of an object to retreave from xml streams. */ protected String rootTagName; /** the root tag of an array of objets to retreave from xml streams. */ protected String arrayRootTagName; /** * the univers of mappers availables, initialized in {@link #initMappers()}. *

* Each mapper of the dictionary is associated to the fully qualified name * of the target class # the tag name or attribute name. *

* Example : *

     *  org.nuiton.util.MyPojo#my-tag
     *  org.nuiton.util.MyPojo#my-attribute
     * 
*/ protected Map allMappers; protected abstract void initMappers() throws IntrospectionException; protected AbstractXpp3Reader(Class type, String rootTagName) { this(type, null, rootTagName); } protected AbstractXpp3Reader(Class type, String arrayRootTagName, String rootTagName) { this.type = type; this.rootTagName = rootTagName; this.arrayRootTagName = arrayRootTagName; allMappers = new TreeMap(); try { initMappers(); } catch (IntrospectionException e) { throw new IllegalStateException( "could not init " + this + " for reason " + e.getMessage(), e); } } @Override public Class getType() { return type; } @Override public String getRootTagName() { return rootTagName; } @Override public void setRootTagName(String rootTagName) { this.rootTagName = rootTagName; } @Override public String getArrayRootTagName() { return arrayRootTagName; } @Override public void setParentRootTagName(String parentRootTagName) { arrayRootTagName = parentRootTagName; } @Override public boolean isAddDefaultEntities() { return addDefaultEntities; } @Override public void setAddDefaultEntities(boolean addDefaultEntities) { this.addDefaultEntities = addDefaultEntities; } @Override public O read(Reader reader) throws IOException, XmlPullParserException { return read(reader, true); } @Override public O read(Reader reader, boolean strict) throws IOException, XmlPullParserException { XmlPullParser parser = new MXParser(); parser.setInput(reader); if (addDefaultEntities) { Xpp3Helper.addDefaultEntities(parser); } parser.next(); // read the first open tag getRootTagName() and consume the matching // ending tag O result = read(getRootTagName(), getType(), parser, strict); // go after the ending tag getRootTagName() parser.next(); // must be at the end of the document checkEndOfXml(parser); return result; } @Override public O[] readArray(Reader reader) throws IOException, XmlPullParserException { return readArray(reader, true); } @Override public O[] readArray(Reader reader, boolean strict) throws IOException, XmlPullParserException { XmlPullParser parser = new MXParser(); parser.setInput(reader); if (addDefaultEntities) { Xpp3Helper.addDefaultEntities(parser); } parser.next(); parser.getEventType(); O[] result = readArray(getArrayRootTagName(), getRootTagName(), getType(), parser, strict ); parser.next(); checkEndOfXml(parser); return result; } /** * Obtain all mappers for a given type. *

* In the result, the keys are now the tag-name of attribute-name. *

* Example : *

     *  my-tag
     *  my-attribute
     * 
* * @param srcType the target type of the searched mappers * @return the dictionnary of mappers for the given type. */ public Map getMappers(Class srcType) { Map result = new TreeMap(); String prefix = srcType.getName() + "#"; for (Entry e : allMappers.entrySet()) { if (e.getKey().startsWith(prefix)) { result.put(e.getValue().getTagName(), e.getValue()); } } return result; } /** * Parse the xml stream from the given parser and a build the associated * object. *

* This default implementation just match a tag text content to a pojo * property. *

* No work is done on attribute values here. *

* Note: The parser must accept as a next open tag the required one . *

* the next node name is given by getRootTagName() *

* Example : *

     * ...
     * <my-pojo>
     *   <my-property>myValue</my-property>
     * </my-pojo>
     * 
* * @param the type of object to build * @param rootTagName the name of the root tag matching the object to build * @param type the type of object to build * @param parser the xpp3 parser * @param strict flag to indicate if should fail if a unknown tag * (or attribute ?) is scanned * @return the single object build from the xml stream. * @throws IOException if any io pb * @throws XmlPullParserException if any parsing pb */ protected T read(String rootTagName, Class type, XmlPullParser parser, boolean strict) throws XmlPullParserException, IOException { // search open tag rootTagName gotoNextOpenTag(rootTagName, parser); // can init result T result = null; try { result = type.newInstance(); } catch (Exception ex) { // should never happens! throw new RuntimeException( "could not instanciate a new " + getType().getName() + " for reason : " + ex.getMessage(), ex); } // prepare alvailable mappers for the given type Map mappers = getMappers(type); Set parsed = new HashSet(); try { // go to next tag int eventType = parser.next(); while (true) { checkNotEndOfXml(parser, rootTagName); if (eventType == XmlPullParser.START_TAG) { // System.out.println("reading tag " + parser.getName()); PropertyMapper mapper = mappers.get(parser.getName()); if (mapper != null) { mapper.setProperty(result, parser, parsed, strict); } else if (strict) { throw new XmlPullParserException( "Unrecognised tag: '" + parser.getName() + "'", parser, null); } } else if (eventType == XmlPullParser.END_TAG) { if (parser.getName().equals(rootTagName)) { // have reach the end of the object break; } } // try next event eventType = parser.next(); } return result; } finally { parsed.clear(); if (mappers != null) { mappers.clear(); } } } /** * Parse the xml stream from the given parser and a build an array of * associated object. *

* This default implementation just match a tag text content to a pojo * property. *

* No work is done on attribute values here. *

* Note: The next node of the parser must be the one given by * {@code parentRootTagName} and sub nodes with names {@code rootTagName}. *

* Example : *

     * ...
     * <my-pojos>
     *   <my-pojo>
     *     <my-property>myValue</my-property>
     *   </my-pojo>
     *   <my-pojo>
     *     <my-property>myValue2</my-property>
     *   </my-pojo>
     * </my-pojos>
     * 
* * @param the type of objects to build * @param parentRootTagName the tag's name of the array container * @param rootTagName the tag's name of each object to build * @param type the type of objects to build * @param parser the xpp3 parser * @param strict flag to indicate if should fail if a unknown * tag (or attribute ?) is scanned * @return the single object build from the xml stream. * @throws IOException if any io pb * @throws XmlPullParserException if any parsing pb */ protected T[] readArray(String parentRootTagName, String rootTagName, Class type, XmlPullParser parser, boolean strict) throws XmlPullParserException, IOException { // search open tag parentRootTagName // if not found, will raise an parsing exception gotoNextOpenTag(parentRootTagName, parser); // can init result List results = new ArrayList(); boolean addChild = false; boolean quit = false; while (!quit) { addChild = false; quit = false; // search next opening tag (rootTagName) or ending tag // (parentRootTagName) while (true) { checkNotEndOfXml(parser, parentRootTagName); // int eventType = parser.getEventType(); int eventType = parser.next(); if (eventType == XmlPullParser.START_TAG && rootTagName.equals(parser.getName())) { // there is a child to read addChild = true; break; } if (eventType == XmlPullParser.END_TAG && parentRootTagName.equals(parser.getName())) { // can quit main loop, end of work quit = true; break; } } if (addChild) { // find an object to add T result = read(rootTagName, type, parser, strict); results.add(result); // go for another round continue; } // no more child // must be at the end of tag if (!quit) { throw new XmlPullParserException( "should be on " + parentRootTagName + " but was not : " + parser.getName()); } } // can not directly instanciate a generic array (or don't known how ?) return results.toArray((T[]) Array.newInstance(type, results.size())); } protected int gotoNextOpenTag(String tagName, XmlPullParser parser) throws XmlPullParserException, IOException { // search next open tag tagName int eventType = parser.getEventType(); while (eventType != XmlPullParser.START_TAG || !parser.getName().equals(tagName)) { checkNotEndOfXml(parser, tagName); eventType = parser.next(); } return eventType; } /** * Checks that a given parser is not at the end of the xml document. * * @param parser the parser to check * @param tagName the endign tag's name * @throws XmlPullParserException if the parser is at the end of the xml * stream, instead of the {@code tagName} * ending tag */ protected void checkNotEndOfXml(XmlPullParser parser, String tagName) throws XmlPullParserException { if (parser.getEventType() == XmlPullParser.END_DOCUMENT) { // can not be here ? throw new XmlPullParserException( "end of document found... but required at least the " + "ending tag " + tagName); } } /** * Checks that a given parser is at the end of the xml document. * * @param parser the parser to check * @throws XmlPullParserException if the parser is not at the end of the * xml stream. */ protected void checkEndOfXml(XmlPullParser parser) throws XmlPullParserException { // must be at the end of the document if (parser.getEventType() != XmlPullParser.END_DOCUMENT) { throw new XmlPullParserException( "should be at the end of document but was not... : " + parser.getName()); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy