Am new to ANTLR framework. I am working with parsing a Java file. Using ANTLR I am generating the JavaLexer, JavaParser, JavaListener, JavaBaseListener uning org.antlr.v4.Tool
Here I have an issue. I create a class that overrides the required methods of JavaBaseListener
Here is the code:
JavaMetaDataReader.java
public class JavaMetaDataReader extends JavaBaseListener{
#Override
public void enterAnnotation(AnnotationContext ctx)
{
System.out.println(ctx.getText());
}
#Override
public void enterAnnotationName(AnnotationNameContext ctx)
{
System.out.println(ctx.getText());
}
#Override
public void enterElementValuePairs(ElementValuePairsContext ctx)
{
System.out.println(ctx.getText());
System.out.println("Parent: "+ctx.getParent().getText());
}
}
JavaReader.Java //Contains the main method.
public class JavaReader {
public static void main(String[] args) {
File fileTobeRead = new File("./src/main/java/sample/HelloWord.java");
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(fileTobeRead);
ANTLRInputStream input = new ANTLRInputStream(fileInputStream);
JavaLexer lexer = new JavaLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
JavaParser parser = new JavaParser(tokens);
ParseTree tree = parser.compilationUnit(); // parse
ParseTreeWalker walker = new ParseTreeWalker(); // create standard walker
JavaMetaDataReader javaMetaDataReader = new JavaMetaDataReader();
walker.walk(javaMetaDataReader, tree); // initiate walk of tree with listener
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
HelloWorld.java
public class HelloWord {
#SuppressWarnings(value = "Helloo")
private void helloWorld() {
// TODO Auto-generated method stub
}
}
Here HelloWorld.java is the file that needs to be parsed.
Here am trying to access the annotations.
The enterAnnotation prints: #SuppressWarnings(value="Helloo")
The enterAnnotationName prints: SuppressWarnings
The first statement in enterElementValuePair prints: value="Helloo"
The second statement in enterElementValuePair prints: Parent: #SuppressWarnings(value="Helloo")
But i need it to print SuppressWarnings (the valure printed by enterAnnotationName
I don't know where I went wrong. I need to access the annotationName inside enterElementValuePairs.
What should I do?
Kindly help me as I am a beginner.
You didn't include a copy of the grammar, so I can only guess about the relation between your rules. It seems the parent of elementValuePairs is annotation, not annotationName. You need to first access the parent (AnnotationContext), and then call AnnotationContext.annotationName() to get the previous sibling of the ElementValuePairsContext.
If you are using the unofficial "optimized" release of the Java target, you can add the following annotation to your enterElementValuePairs method to ensure that a compiler error is reported if you later use the elementValuePairs rule in a way which would break this. Note that this requires the #version{} action to be used when the grammar is modified, as described in the link below.
#RuleDependencies({
#RuleDependency(recognizer=JavaParser.class, rule=JavaParser.RULE_elementValuePairs,
version=0, dependents={Dependents.PARENTS, Dependents.DESCENDANTS}),
#RuleDependency(recognizer=JavaParser.class, rule=JavaParser.RULE_annotation,
version=0, dependents=Dependents.SELF),
#RuleDependency(recognizer=JavaParser.class, rule=JavaParser.RULE_annotationName,
version=0, dependents=Dependents.DESCENDANTS)
})
More information about using rule dependencies is available here:
https://github.com/sharwell/antlr4/wiki/Rule-Versioning
Related
Does Apache Velocity include a mechanism for adding metadata to a template?
I'm trying to add some extra information to my templates (e.g., type and descriptive name), and then read those to programmatically group templates by type, and list the templates on the UI using their descriptive name.
I've tried to use literal #[[...]]# blocks (and parse them), and #set directives, but both a have issues. They are hacky (require some parsing of the template) and far from elegant.
Hmmm, I'm not aware of anything built-in to do this. To avoid processing a whole template on a first pass though, one trick is to conditionally throw an exception (MetadataFinished below) during that pass, but not normal execution.
Clearly this would still need to compile the whole template up front, though this should come in useful at execution time.
E.g.
import org.apache.commons.io.output.NullWriter;
public class Metadata {
private Map<String, Template> byKey = new LinkedHashMap<>();
private Template currentTemplate;
/** Callback from .vm */
public void set(String key) throws MetadataFinished {
// Only do this in addTemplate()
if (currentTemplate != null) {
byKey.put(key, currentTemplate);
throw new MetadataFinished();
}
}
public void addTemplate(Template template) {
currentTemplate = template;
try {
Context context = new VelocityContext();
context.put("metadata", this);
template.merge(context, new NullWriter());
} catch (MetadataFinished ex) {
// Ignored
} finally {
currentTemplate = null;
}
}
public void execute(String key) {
Template template = byKey.get(key);
Context context = new VelocityContext();
PrintWriter pw = new PrintWriter(System.out);
template.merge(context, pw);
pw.flush();
}
// Extends Error to avoid Velocity adding a wrapping MethodInvocationException
private static class MetadataFinished extends Error {
}
public static void main(String[] args) {
Metadata metadata = new Metadata();
VelocityEngine engine = new VelocityEngine();
engine.setProperty("file.resource.loader.path", "/temp");
engine.init();
String[] fileNames = { "one.vm", "two.vm" };
for (String fileName : fileNames) {
Template template = engine.getTemplate(fileName);
metadata.addTemplate(template);
}
metadata.execute("vm1");
metadata.execute("vm2");
}
}
Then in one.vm:
$!metadata.set("vm1")##
-----------
This is VM1
-----------
The ## there is a bit ugly - it's just to stop a blank line being output. If readability is important, this can be made a bit neater with a macro though:
#metadata("vm2")
-----------
This is VM2
-----------
That macro could be defined in the global VM_global_library.vm:
#macro( metadata $key )
$!metadata.set($key)#end
Just for reference, the output is as expected:
-----------
This is VM1
-----------
-----------
This is VM2
-----------
For a project at university, I need to parse a GML file. GML files are XML based so I use JDOM2 to parse it. To fit my purposes, I extended org.jdom2.Document like so:
package datenbank;
import java.io.File;
// some more imports
public class GMLDatei extends org.jdom2.Document {
public void saveAsFile() {
// ...
}
public GMLKnoten getRootElement(){
return (GMLKnoten) this.getDocument().getRootElement();
}
public void setRootElement(GMLKnoten root){
this.getDocument().setRootElement(root);
}
}
I also extended org.jdom2.Element and named the subclass GMLKnoten but this does not matter too much for my question.
When testing, I try to load a GML file. When using the native document and element classes, it loads fine, but when using my subclasses, I get the following scenario:
I load the file using:
SAXBuilder saxBuilder = new SAXBuilder();
File inputFile = new File("gml/Roads_Munich_Route_Lines.gml");
GMLDatei document = null;
ArrayList<String> types = new ArrayList<String>();
try {
document = (GMLDatei) saxBuilder.build(inputFile);
} catch (JDOMException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
In the line
document = (GMLDatei) saxBuilder.build(inputFile);
I get a Cast-Exception:
Exception in thread "main" java.lang.ClassCastException: org.jdom2.Document cannot be cast to datenbank.GMLDatei
at datenbank.GMLTest.main(GMLTest.java:27)
I thought that casting schould be no problem as I am subclassing org.jdom2.document. What am I missing?
vat
In general I want to "challenge" your requirement to extend Document - what value do you get from your custom classes that are not already part of the native implementation? I ask this for 2 reasons:
as the maintainer of JDOM, should I be adding some new feature?
I am just curious.....
JDOM has a system in place for allowing you to extend it's core classes and have a different implementation of them when parsing a document. It is done by extending the JDOMFactory.
Consider this code here: JDOMFactory interface. When SAXParser parses a document it uses those methods to build the document.
There is a default, overridable implementation in DefaultJDOMFactory that you can extend, and, for example, in your implementation, you must override the non-final "Element" methods like:
#Override
public Element element(final int line, final int col, final String name,
String prefix, String uri) {
return new Element(name, prefix, uri);
}
and instead have:
#Override
public Element element(final int line, final int col, final String name,
String prefix, String uri) {
return new GMLKnoten (name, prefix, uri);
}
Note that you will have to override all methods that are non-final and return content that is to be customised (for example, you will have to override 4 Element methods by my count.
With your own GMLJDOMFactory you can then use SAXBuilder by either using the full constructor new SAXBuilder(null, null, new GMPJDOMFactory()) or by setting the JDOMFactory after you have constructred it with setJDOMFactory(...)
I'm getting an error when I'm trying to access server-side's GreetingServiceImpl class and try to use a function of it in client-side.
ERROR: No source code is available for type com.demo1.server.GreetingServiceImpl; did you forget to inherit a required module?
Here is the GreetingServiceImpl:
public class GreetingServiceImpl extends RemoteServiceServlet implements
GreetingService {
public LinkedList<String> greetServer() throws IllegalArgumentException {
// Verify that the input is valid.
LinkedList<String> list = new LinkedList<String>();
try {
File file = getLog();
Parse parse = new Parse(file);
list = parse.callControlRequest();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return list;
}
public File getLog() throws IOException {
//doing something
}
}
and I'm trying to use it in client-side like:
GreetingServiceImpl resultList = new GreetingServiceImpl(); //this is where I am getting error
greetingService.greetServer(new AsyncCallback>() {
#Override
public void onFailure(Throwable caught) {
// TODO Auto-generated method stub
dialogBox
.setText("Remote Procedure Call - Failure");
dialogBox.center();
}
#Override
public void onSuccess(LinkedList<String> result) {
result=resultList.greetServer(); // this is where I am trying to get the output of it
}
});;
}
You cannot use classes from your server side on client side. To use GreetingService you should instantiate it's async part:
GreetingServiceAsync greetingService = GWT.create(GreetingService.class);
then you could use greetingService variable to call methods in GreetingServiceImpl - you can't use or refer GreetingServiceImpl directly on client side, so line
GreetingServiceImpl resultList = new GreetingServiceImpl();
is illegal - remove it.
Also you can generate default gwt application and look how it's done there or look at DynaTable sample provided with gwt library: gwt-dir/samples/DynaTable.
I have the following class:
public class FileLoader {
private Map<Brand, String> termsOfUseText = new HashMap<Brand, String>();
public void load() {
for (Brand brand : Brand.values()) {
readAndStoreTermsOfUseForBrand(brand);
}
}
private void readAndStoreTermsOfUseForBrand(Brand brand) {
String resourceName = "termsOfUse/" + brand.name().toLowerCase() + ".txt";
InputStream in = this.getClass().getClassLoader().getResourceAsStream(resourceName);
try {
String content = IOUtils.toString(in);
termsOfUseText.put(brand, content);
} catch (IOException e) {
throw new IllegalStateException(String.format("Failed to find terms of use source file %s", resourceName),e);
}
}
public String getTextForBrand(Brand brand) {
return termsOfUseText.get(brand);
}
}
Brand is an enum, and I need all the valid .txt files to be on the classpath. How do I make the IOException occur, given that the Brand enum contains all the valid brands and therfore all the .txt files for them exist?
Suggestions around refactoring the current code are welcome if it makes it more testable!
Three options I see right off:
Use PowerMock to mock IOUtils.toString(). I consider PowerMock to be quite a last resort. I'd rather refactor the source to something a little more test-friendly.
Extract the IOUtils call to a protected method. Create a test-specific subclass of your class that overrides this method and throws the IOException.
Extract the InputStream creation to a protected method. Create a test-specific subclass to override the method and return a mock InputStream.
I would suggest a bit of refactoring. All your methods are void, this usually means they are not functional.
For example, you can extract this functionality:
private String readTermsOfUseForBrand(InputStream termsOfUserIs) {
try {
String content = IOUtils.toString(in);
return content;
} catch (IOException e) {
throw new IllegalStateException(String.format("Failed to find terms of use source file %s", resourceName), e);
}
return null;
}
So that we can assert on the String result in our tests.
Of course this is not functional code, as it reads from an Input Stream. And it does so with IOUtils.toString() method that cannot be mocked easily (well, there's PowerMock but as Ryan Stewart said it's the last resort).
To test IO exceptions you can create a failing input stream (tested with JDK7):
public class FailingInputStream extends InputStream {
#Override
public int read() throws IOException {
throw new IOException("Test generated exception");
}
}
And test like that:
#Test
public void testReadTermsOfUseForBrand() {
FileLoader instance = new FileLoader();
String result = instance.readTermsOfUseForBrand(new FailingInputStream());
assertNull(result);
}
Missing file will cause NullPointerException because getResourceAsStream will return null and you will have in==null. IOException in this case may actually be pretty rare. If it's critical for you to see it, I can only think of instrumenting this code to throw it if code is executed in test scope. But is it really that important?
I would use a mock to accomplish this.
Example (untested, just to give you some thought):
#Test(expected=IllegalStateException.class)
public void testThrowIOException() {
PowerMockito.mockStatic(IOUtils.class);
PowerMockito.when(IOUtils.toString()).thenThrow(
new IOException("fake IOException"));
FileLoader fileLoader = new FileLoader();
Whitebox.invokeMethod(fileLoader,
"readAndStoreTermsOfUseForBrand", new Brand(...));
// If IllegalStateException is not thrown then this test case fails (see "expected" above)
}
Code below is completely untested
To cause the IOException use:
FileInputStream in = this.getClass().getClassLoader().getResourceAsStream(resourceName);
in.mark(0);
//read some data
in.reset(); //IOException
To test the IOException case use:
void test
{
boolean success = false;
try
{
//code to force ioException
}
catch(IOException ioex)
{
success = true;
}
assertTrue(success);
}
In JUnit4
#Test(expected=IOException.class)
void test
{
//code to force ioException
}
Other JUnit
void test
{
try
{
//code to force IOException
fail("If this gets hit IO did not occur, fail test");
}
catch(IOException ioex)
{
//success!
}
}
my system is both jibx and a legacy xml app and i want to build a constructor that can take a string of xml and unmarshal it into its own class. like this:
public ActiveBankTO(String xmlIn)
{
try
{
ByteArrayInputStream bin = new ByteArrayInputStream(xmlIn.getBytes());
IBindingFactory bfact;
bfact = BindingDirectory.getFactory(ActiveBankTO.class);
IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
this = (ActiveBankTO) uctx.unmarshalDocument(bin, null);
} catch (JiBXException e)
{
e.printStackTrace();
}
}
but obviously i cant assign "this" as a variable. is there a way to make this work? i realize i can put this into a static method that can be used, or a few other tricks to make it work, but this is something that has come up on several projects in various forms and i was wondering if this particular method is possible.
No, it's not possible. The static method solution is the best idea.
public static ActiveBankTO parseActiveBankTO(String xmlIn) {
ActiveBankTO newTO = null;
try {
ByteArrayInputStream bin = new ByteArrayInputStream(xmlIn.getBytes());
IBindingFactory bfact;
bfact = BindingDirectory.getFactory(ActiveBankTO.class);
IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
newTO = (ActiveBankTO) uctx.unmarshalDocument(bin, null);
} catch (JiBXException e) {
e.printStackTrace();
}
return newTO;
}
No. ti's not possible in the constructor. A static factory method is the only real way (you can't even cheat like this in bytecode).