org.nuiton.io.xpp3.AbstractXpp3Reader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of maven-helper-plugin Show documentation
Show all versions of maven-helper-plugin Show documentation
Plugin d'aide pour les projets nuiton
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