Capture xsl:message output in java - java

I'm trying to capture xsl:message in java when calling my transform. Below is a snippet of my code.
final ArrayList<TransformerException> errorList = new ArrayList<TransformerException>();
ErrorListener errorListener = new ErrorListener() {
#Override
public void warning(TransformerException e) throws TransformerException {
//To change body of implemented methods use File | Settings | File Templates.
log.error(e.getMessage());
errorList.add(e);
}
#Override
public void error(TransformerException e) throws TransformerException {
//To change body of implemented methods use File | Settings | File Templates.
log.error(e.getMessage());
errorList.add(e);
}
#Override
public void fatalError(TransformerException e) throws TransformerException {
//To change body of implemented methods use File | Settings | File Templates.
errorList.add(e);
throw e;
}
};
...
try
{
transformer.setErrorListener(errorListener);
newDoc = transform(transformer, oldDoc);
}
catch (TransformerException e) {
log.error("Problem transforming normalized document into PUBS-XML", e);
throw e;
}
Unfortunately this is not working.
Is there a better way?
Thanks in advance!

If you are using Saxon, then you may need to set the message emitter using setMessageEmitter().
https://www.saxonica.com/html/documentation10/javadoc/net/sf/saxon/trans/XsltController.html#setMessageEmitter-net.sf.saxon.event.Receiver-
public void setMessageEmitter(Receiver receiver)
Set the Receiver to be used for xsl:message output.
Recent versions of the JAXP interface specify that by default the
output of xsl:message is sent to the
registered ErrorListener. Saxon does
not implement this convention.
Instead, the output is sent to a
default message emitter, which is a
slightly customised implementation of
the standard Saxon Emitter interface.
This interface can be used to change the way in which Saxon outputs
xsl:message output.
Michael Kay has explained why Saxon doesn't output xsl:message according to the JAXP interface, and has suggested two options for obtaining the output:
ErrorListener was something that was
introduced to JAXP at a rather late
stage (one of many regrettable
occasions where the spec was changed
unilaterally to match the Xalan
implementation), and I decided not to
implement this change as a default
behaviour, because it would have been
disruptive to existing applications.
In Saxon, xsl:message output is
directed to a Receiver, which you can
nominate to the Transformer:
((net.sf.saxon.Controller)transformer).setMessageEmitter(....)
If you want to follow the JAXP model
of sending the output to the
ErrorListener, you can nominate a
Receiver that does this:
((net.sf.saxon.Controller)transformer).setMessageEmitter(new net.sf.saxon.event.MessageWarner())

Related

SAX parser does not call startDTD

I have followed Obtaining DOCTYPE details using SAX (JDK 7), implementing it like this:
public class MyXmlReader {
public static void parse(InputSource inputSource) {
try {
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
MyContentHandler handler = new MyContentHandler();
xmlReader.setContentHandler(handler);
xmlReader.setProperty("http://xml.org/sax/properties/lexical-handler", handler); // Does not work; handler is set, but startDTD/endDTD is not called
xmlReader.setDTDHandler(handler);
xmlReader.setErrorHandler(new MyErrorHandler());
xmlReader.setFeature("http://xml.org/sax/features/validation", false);
xmlReader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
xmlReader.parse(inputSource);
}
catch (SAXException e) {
throw new MyImportException("Error while parsing file", e);
}
}
}
MyContentHandler extends DefaultHandler2, but neither startDTD nor endDTD is called (but e.g. startEntity is in fact called, so the lexical handler is set).
I have tried to leave the features out, but this changes nothing.
What goes wrong here?
I am using Java 8 JDK 1.8.0_144.
The XML looks like this:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE MyMessage SYSTEM "http://www.testsite.org/mymessage/5.1/reference/international.dtd">
<MyMessage>
<Header>
...
According to XMLReader API you need to set a DTD Handler, otherwise DTD Events will be silently ignored. A DefaultHandler2 yet implements DTDHandler interface, so you could use xmlReader.setDTDHandler(handler); again;

How to make newlines between attributes in XML file by using dom4j?

I want to generate a xml file in the following format by using java :
each attribute should be in separate line.
<parameters>
<parameter
name="Tom"
city="York"
number="123"
/>
</parameters>
But I can only get all attributes in one line
<parameters>
<parameter name="Tom" city="York" number="123"/>
</parameters>
I'm using dom4j, could anyone tell how I can make it? Does dom4j supports this kind of format?
Thanks.
You cannot do it with the XMLWriter unless you want to substantially rewrite the main logic. However, since XMLWriter is also a SAX ContentHandler it can consume SAX events and serialize them to XML, and in this mode of operation, XMLWriteruses a different code path which is easier to customize. The following sub class will give you almost what you want, except that empty elements will not use the short form <element/>. Maybe that can be fixed by further tweaking.
static class ModifiedXmlWriter extends XMLWriter {
// indentLevel is private, need reflection to read it
Field il;
public ModifiedXmlWriter(OutputStream out, OutputFormat format) throws UnsupportedEncodingException {
super(out, format);
try {
il = XMLWriter.class.getDeclaredField("indentLevel");
il.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
int getIndentLevel() {
try {
return il.getInt(this);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
#Override
protected void writeAttributes(Attributes attributes) throws IOException {
int l = getIndentLevel();
setIndentLevel(l+1);
super.writeAttributes(attributes);
setIndentLevel(l);
}
#Override
protected void writeAttribute(Attributes attributes, int index) throws IOException {
writePrintln();
indent();
super.writeAttribute(attributes, index);
}
}
public static void main(String[] args) throws Exception {
String XML = "<parameters>\n" +
" <parameter name=\"Tom\" city=\"York\" number=\"123\"/>\n" +
"</parameters>";
Document doc = DocumentHelper.parseText(XML);
XMLWriter writer = new ModifiedXmlWriter(System.out, OutputFormat.createPrettyPrint());
SAXWriter sw = new SAXWriter(writer);
sw.write(doc);
}
Sample output:
<?xml version="1.0" encoding="UTF-8"?>
<parameters>
<parameter
name="Tom"
city="York"
number="123"></parameter>
</parameters>
Generally speaking, very few XML serializers give you this level of control over the output format.
You can get something close to this with the Saxon serializer if you specify the options method=xml, indent=yes, saxon:line-length=20. The Saxon serializer is capable of taking a DOM4J tree as input. You will need Saxon-PE or -EE because it requires a serialization parameter in the Saxon namespace. It still won't be exactly what you want because the first attribute will be on the same line as the element name and the others will be vertically aligned underneath the first.

Why does wrapping an exception still request try-catch even when adding a throws?

I'm making use of SikuliX's API within my own personal library. The idea is to reference my library alone in external projects which incorporates the parts of SikuliX that I require.
Now, SikuliX throwns a FindFailed exception, which I required. I tried to do:
public class FindFailed extends org.sikuli.script.FindFailed {
FindFailed(String msg) { super(msg); }
}
Which seemed to make sense. However, when attempting to use a throws statement in one of the methods:
import org.mylibrary.exceptions.FindFailed;
public static boolean clickFinishButton() throws FindFailed {
pattern = PatternManager.loadPattern("my-image.png");
screen.wait(pattern, 10);
region = screen.exists(pattern);
region.click(pattern);
return true;
}
I still get an Unhandled exception type FindFailed warning. Changing it back to the original org.sikuli.script.FindFailed will of course work, however making use of try-catch in an external project will require me to re-add the relevant SikuliX jar file.
What I would like to do, is simply wrap the FindFailed exception that is being thrown by SikuliX and use it internally and externally with my library.
The primary goal of all of this is to wrap around another API with my own additional methods and such, so that when I reference this library, the later projects don't have to reference SikuliX's jar as well.
- - - - My Library - - - <—————— External Project
| |
| SikuliX |
- - - - - - - - - - - -
As is it right now, I require to do the following:
- - - - My Library - - - <—————— External Project
| | |
| SikuliX | |
- - - - - - - - - - - - v
SikuliX (Again)
So far I've changed things as follows which seems to work.
public class FindFailed extends Exception {
public FindFailed(Throwable cause) { super(cause); }
}
I now don't extend any third party Exceptions. And instead I proceed by doing the following:
public static boolean clickNewScan() throws FindFailed {
pattern = PatternManager.loadPattern("my-image.png");
region = screen.exists(pattern);
try {
screen.wait(pattern, 60);
region.click(pattern);
} catch (org.sikuli.script.FindFailed e) {
throw new FindFailed(e);
}
return true;
}
You do this by wrapping all the calls in SikuliX their own interfaces. I don't know SikuliX, so I'll make a toy example.
package third.party.library;
public class Foo {
public void doSomething() throws ThirdPartyException {
// Their code
}
}
Okay, so you want to wrap this functionality without depending on their library.
package juxhin;
public interface FooBehavior {
public void doSomething() throws MyException;
}
Then, when you need their behavior, you can use your own implementation:
package juxhin; // YOU write this class
public class ThirdPartyFooBehavior implements FooBehavior {
private final Foo foo;
public FooThirdPartyFooBehavior(Foo theirObject) {
this.foo = theirObject;
}
#Override
public void doSomething() throws MyException {
try {
foo.doSomething();
} catch (ThirdPartyException e) {
throw new MyException(e);
}
}
}
Once you've wrapped their library behind all your own interfaces, then your classes only will only depend on your own interfaces, which means you won't have to worry about their exceptions. Their library will be completely removable as long as you reimplement these interfaces with a non-dependent implementation.
Note that MyException should not extend third.party.library.ThirdPartyException, because that won't help your problem; it should use the Exception(Throwable cause) constructor and remove it from the org.sikuli.script class hierarchy.
The bottom line, though, is that you still have to include the code included in SikuliX somehow. This is why tools like Maven exist, so that adding the reference to jars is very easy. For example, if your jar is dependent on SikuliX, then when you tell your new project to use your jar, it will automatically include the SikuliX reference without you having to do anything. You end up with dependency trees like this, which automatically do all this work for you:
I personally use Maven but there are other options like Ivy and Gradle that do the same thing - I'm not trying to advocate for any particular tool here, just advocating for using any dependency tool.
Extending from classes you don't own is never a good idea and should be avoided. Besides, it would make whoever handles your exception still have the jar that contains org.sikuli.script.FindFailed.
A better approach would be wrapping the exception like this:
public class MyFindFailedException extends Exception {
MyFindFailedException(String message, Exception cause) {
super(message, cause);
}
}
And then use it like this:
public static boolean clickFinishButton() throws MyFindFailedException {
try {
pattern = PatternManager.loadPattern("my-image.png");
screen.wait(pattern, 10);
region = screen.exists(pattern);
region.click(pattern);
return true;
} catch (FindFailed e) {
throw new MyFindFailedException("something went wrong", e);
}
}

How to extract useful information from TransformerException

I am using javax.xml.transform.* to do XSLT transformation. Since the xslt file to be used comes from the outside world there could be errors in that file, and I am going to give back some meaningful response to the user.
Although I can easily catch the TransformationExceptions, I found no way to obtain enough information from it. For example, if there is a tag to be terminated by an end-tag, printStackTrace() gives scarring message
javax.xml.transform.TransformerConfigurationException: Could not compile stylesheet
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl.newTemplates(Unknown Source)
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl.newTransformer(Unknown Source)
... (100 lines)
and getMessage() gives only
Could not compile stylesheet
None of them gives the real reason of the error.
I noticed that in Eclipse test console I can see the following
[Fatal Error] :259:155: The element type "sometag" must be terminated by the matching end-tag "</sometag>".
ERROR: 'The element type "sometag" must be terminated by the matching end-tag "</sometag>".'
FATAL ERROR: 'Could not compile stylesheet'
This is exactly what I want. Unfortunately, since this is a web application, the user cannot see this.
How can I display the correct error message to the user?
Put your own ErrorListener on your Transformer instance using Transformer.setErrorListener, like so:
final List<TransformationException> errors = new ArrayList<TransformationException>();
Transformer transformer = ... ;
transformer.setErrorListener(new ErrorListener() {
#Override
public void error(TransformerException exception) {
errors.add(exception);
}
#Override
public void fatalError(TransformerException exception) {
errors.add(exception);
}
#Override
public void warning(TransformerException exception) {
// handle warnings as well if you want them
}
});
// Any other transformer setup
Source xmlSource = ... ;
Result outputTarget = ... ;
try {
transformer.transform(xmlSource, outputTarget);
} catch (TransformerException e) {
errors.add(e); // Just in case one is thrown that isn't handled
}
if (!errors.isEmpty()) {
// Handle errors
} else {
// Handle output since there were no errors
}
This will log all the errors that occur into the errors list, then you can use the messages off those errors to get what you want. This has the added benefit that it will try to resume the transformation after the errors occur. If this causes any problems, just rethrow the exception by doing:
#Override
public void error(TransformerException exception) throws TransformationException {
errors.add(exception);
throw exception;
}
#Override
public void fatalError(TransformerException exception) throws TransformationException {
errors.add(exception);
throw exception;
}
Firstly, it's likely that any solution will dependent on your choice of XSLT processor. Different implementations of the JAXP interface might well provide different information in the exceptions they generate.
It's possible that the error from the XML parser is available in a wrapped exception. For historic reasons, TransformerConfigurationException offers both getException() and getCause() to access wrapped exceptions, and it may be worth checking them both.
Alternatively it's possible that the information was supplied in a separate call to the ErrorListener.
Finally, this particular error is detected by the XML parser (not the XSLT processor) so in the first instance it will be handled by the parser. It may well be worth setting the parser's ErrorHandler and catching parsing errors at that level. If you want explicit control over the XML parser used by the transformation, use a SAXSource whose XMLReader is suitably initialized.
You can configure System.out to write in your own OutputStream.
Use of ErrorListener don't catch all output.
If you work with threads you can look here (http://maiaco.com/articles/java/threadOut.php) to avoid change of System.out for other threads.
example
public final class XslUtilities {
private XslUtilities() {
// only static methods
}
public static class ConvertWithXslException extends Exception {
public ConvertWithXslException(String message, Throwable cause) {
super(message, cause);
}
}
public static String convertWithXsl(String input, String xsl) throws ConvertWithXslException {
ByteArrayOutputStream systemOutByteArrayOutputStream = new ByteArrayOutputStream();
PrintStream oldSystemOutPrintStream = System.out;
System.setOut(new PrintStream(systemOutByteArrayOutputStream));
ByteArrayOutputStream systemErrByteArrayOutputStream = new ByteArrayOutputStream();
PrintStream oldSystemErrPrintStream = System.err;
System.setErr(new PrintStream(systemErrByteArrayOutputStream));
String resultXml;
try {
System.setProperty("javax.xml.transform.TransformerFactory", "net.sf.saxon.TransformerFactoryImpl");
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer(new StreamSource(new StringReader(xsl)));
StringWriter stringWriter = new StringWriter();
transformer.transform(new StreamSource(new StringReader(input)), new StreamResult(stringWriter));
resultXml = stringWriter.toString();
} catch (TransformerException e) {
System.out.flush();
final String systemOut = systemOutByteArrayOutputStream.toString();
System.err.flush();
final String systemErr = systemErrByteArrayOutputStream.toString();
throw new ConvertWithXslException("TransformerException - " + e.getMessageAndLocation()
+ (systemOut.length() > 0 ? ("\nSystem.out:" + systemOut) : "")
+ (systemErr.length() > 0 ? ("\nSystem.err:" + systemErr) : ""), e);
} finally {
System.setOut(oldSystemOutPrintStream);
System.setErr(oldSystemErrPrintStream);
}
return resultXml;
}
}

Java annotation processing with source code manipulation

I have been looking for a solution for below requirement -
Source files are written with Custom Annotation on a method
Method body needs a little variation based on the annotation.
Source file should not be changed, but input to compiler should be modified source file
I have looked at below APIs -
javax.annotation.processing - Annotation processing.
javax.lang.model.* - Language model used in annotation processing and Compiler Tree API
com.sun.source.* - Compiler Tree API.
I thought of designing this by following :
Write an annotation processor
Generate the compiler tree
Edit the compiler tree at runtime without affecting origional source file
Supply the tree to compiler
Compiler Tree API appears to be promissing where it gives access to
com.sun.source.tree.MethodTree
However compiler Tree API appears to be Read Only.
I can not figure out how to acomplish the steps 3 & 4
Is there any API for this which I can adopt to acomplish the task
NOTE: I am looking for only Source Code manipulation technique. No runtime byte code manipulation / AOP
Environment: Java 6
The standard annotation processing API does not support direct modification of source code. However, some of the effects of modifying source code can be had by generating either the superclass or subclass(es) of the annotated type. The blog entry below shows an example of this technique:
"Properties via Annotation Processing"
You can do this as something below which will let you accomplish 3) and 4).
Example taken from java annotation processor example
#SupportedAnnotationTypes( "com.javacodegeeks.advanced.processor.Immutable" )
#SupportedSourceVersion( SourceVersion.RELEASE_7 )
public class SimpleAnnotationProcessor extends AbstractProcessor {
#Override
public boolean process(final Set< ? extends TypeElement > annotations,
final RoundEnvironment roundEnv) {
for( final Element element: roundEnv.getElementsAnnotatedWith( Immutable.class ) ) {
if( element instanceof TypeElement ) {
final TypeElement typeElement = ( TypeElement )element;
for( final Element eclosedElement: typeElement.getEnclosedElements() ) {
if( eclosedElement instanceof VariableElement ) {
final VariableElement variableElement = ( VariableElement )eclosedElement;
if( !variableElement.getModifiers().contains( Modifier.FINAL ) ) {
processingEnv.getMessager().printMessage( Diagnostic.Kind.ERROR,
String.format( "Class '%s' is annotated as #Immutable,
but field '%s' is not declared as final",
typeElement.getSimpleName(), variableElement.getSimpleName()
)
);
}
}
}
}
// Claiming that annotations have been processed by this processor
return true;
}
}
Another way using projectlombok with custom handler.
Example built in handler from GitHub Project Lombok.
This annotation adds try catch block
public class SneakyThrowsExample implements Runnable {
#SneakyThrows(UnsupportedEncodingException.class)
public String utf8ToString(byte[] bytes) {
return new String(bytes, "UTF-8");
}
#SneakyThrows
public void run() {
throw new Throwable();
}
}
This gets processed to
public String utf8ToString(byte[] bytes) {
try {
return new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw Lombok.sneakyThrow(e);
}
}
public void run() {
try {
throw new Throwable();
} catch (Throwable t) {
throw Lombok.sneakyThrow(t);
}
}
You can find the Handler code on the same Github/lombok site.
I would suggest you copy all of the source code to a separate directory, modify the code there and build from the temporary path.

Categories

Resources