BAEL-1732 - Java with ANTLR (#4243)
Examples for Java with ANTLR article
This commit is contained in:
parent
d1e092b850
commit
287d0a062a
|
@ -0,0 +1,66 @@
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>antlr</artifactId>
|
||||||
|
<name>antlr</name>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<artifactId>parent-modules</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.antlr</groupId>
|
||||||
|
<artifactId>antlr4-maven-plugin</artifactId>
|
||||||
|
<version>${antlr.version}</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>antlr4</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>build-helper-maven-plugin</artifactId>
|
||||||
|
<version>${mojo.version}</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>generate-sources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>add-source</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<sources>
|
||||||
|
<source>${basedir}/target/generated-sources/antlr4</source>
|
||||||
|
</sources>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.antlr</groupId>
|
||||||
|
<artifactId>antlr4-runtime</artifactId>
|
||||||
|
<version>${antlr.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>${junit.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<properties>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
<antlr.version>4.7.1</antlr.version>
|
||||||
|
<junit.version>4.12</junit.version>
|
||||||
|
<mojo.version>3.0.0</mojo.version>
|
||||||
|
</properties>
|
||||||
|
</project>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,16 @@
|
||||||
|
grammar Log;
|
||||||
|
|
||||||
|
log : entry+;
|
||||||
|
entry : timestamp ' ' level ' ' message CRLF;
|
||||||
|
timestamp : DATE ' ' TIME;
|
||||||
|
level : 'ERROR' | 'INFO' | 'DEBUG';
|
||||||
|
message : (TEXT | ' ')+;
|
||||||
|
|
||||||
|
fragment DIGIT : [0-9];
|
||||||
|
fragment TWODIGIT : DIGIT DIGIT;
|
||||||
|
fragment LETTER : [A-Za-z];
|
||||||
|
|
||||||
|
DATE : TWODIGIT TWODIGIT '-' LETTER LETTER LETTER '-' TWODIGIT;
|
||||||
|
TIME : TWODIGIT ':' TWODIGIT ':' TWODIGIT;
|
||||||
|
TEXT : LETTER+;
|
||||||
|
CRLF : '\r'? '\n' | '\r';
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.baeldung.antlr.java;
|
||||||
|
|
||||||
|
import com.baeldung.antlr.Java8BaseListener;
|
||||||
|
import com.baeldung.antlr.Java8Parser;
|
||||||
|
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class UppercaseMethodListener extends Java8BaseListener {
|
||||||
|
|
||||||
|
private List<String> errors = new ArrayList<String>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void enterMethodDeclarator(Java8Parser.MethodDeclaratorContext ctx) {
|
||||||
|
TerminalNode node = ctx.Identifier();
|
||||||
|
String methodName = node.getText();
|
||||||
|
|
||||||
|
if (Character.isUpperCase(methodName.charAt(0))){
|
||||||
|
errors.add(String.format("Method %s is uppercased!", methodName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getErrors(){
|
||||||
|
return Collections.unmodifiableList(errors);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package com.baeldung.antlr.log;
|
||||||
|
|
||||||
|
import com.baeldung.antlr.LogBaseListener;
|
||||||
|
import com.baeldung.antlr.LogParser;
|
||||||
|
import com.baeldung.antlr.log.model.LogLevel;
|
||||||
|
import com.baeldung.antlr.log.model.LogEntry;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public class LogListener extends LogBaseListener {
|
||||||
|
|
||||||
|
private static final DateTimeFormatter DEFAULT_DATETIME_FORMATTER
|
||||||
|
= DateTimeFormatter.ofPattern("yyyy-MMM-dd HH:mm:ss", Locale.ENGLISH);
|
||||||
|
|
||||||
|
private List<LogEntry> entries = new ArrayList<>();
|
||||||
|
private LogEntry currentLogEntry;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void enterEntry(LogParser.EntryContext ctx) {
|
||||||
|
this.currentLogEntry = new LogEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exitEntry(LogParser.EntryContext ctx) {
|
||||||
|
entries.add(currentLogEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void enterTimestamp(LogParser.TimestampContext ctx) {
|
||||||
|
currentLogEntry.setTimestamp(LocalDateTime.parse(ctx.getText(), DEFAULT_DATETIME_FORMATTER));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void enterMessage(LogParser.MessageContext ctx) {
|
||||||
|
currentLogEntry.setMessage(ctx.getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void enterLevel(LogParser.LevelContext ctx) {
|
||||||
|
currentLogEntry.setLevel(LogLevel.valueOf(ctx.getText()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<LogEntry> getEntries() {
|
||||||
|
return Collections.unmodifiableList(entries);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.baeldung.antlr.log.model;
|
||||||
|
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
public class LogEntry {
|
||||||
|
|
||||||
|
private LogLevel level;
|
||||||
|
private String message;
|
||||||
|
private LocalDateTime timestamp;
|
||||||
|
|
||||||
|
public LogLevel getLevel() {
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLevel(LogLevel level) {
|
||||||
|
this.level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimestamp(LocalDateTime timestamp) {
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.baeldung.antlr.log.model;
|
||||||
|
|
||||||
|
public enum LogLevel {
|
||||||
|
DEBUG, INFO, ERROR
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package com.baeldung.antlr;
|
||||||
|
|
||||||
|
import com.baeldung.antlr.java.UppercaseMethodListener;
|
||||||
|
import org.antlr.v4.runtime.CharStreams;
|
||||||
|
import org.antlr.v4.runtime.CommonTokenStream;
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTreeWalker;
|
||||||
|
import org.junit.Test;
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
public class JavaParserUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenOneMethodStartsWithUpperCase_thenOneErrorReturned() throws Exception{
|
||||||
|
|
||||||
|
String javaClassContent = "public class SampleClass { void DoSomething(){} }";
|
||||||
|
Java8Lexer java8Lexer = new Java8Lexer(CharStreams.fromString(javaClassContent));
|
||||||
|
CommonTokenStream tokens = new CommonTokenStream(java8Lexer);
|
||||||
|
Java8Parser java8Parser = new Java8Parser(tokens);
|
||||||
|
ParseTree tree = java8Parser.compilationUnit();
|
||||||
|
ParseTreeWalker walker = new ParseTreeWalker();
|
||||||
|
UppercaseMethodListener uppercaseMethodListener = new UppercaseMethodListener();
|
||||||
|
walker.walk(uppercaseMethodListener, tree);
|
||||||
|
|
||||||
|
assertThat(uppercaseMethodListener.getErrors().size(), is(1));
|
||||||
|
assertThat(uppercaseMethodListener.getErrors().get(0),
|
||||||
|
is("Method DoSomething is uppercased!"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.baeldung.antlr;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
import com.baeldung.antlr.log.LogListener;
|
||||||
|
import com.baeldung.antlr.log.model.LogLevel;
|
||||||
|
import com.baeldung.antlr.log.model.LogEntry;
|
||||||
|
import org.antlr.v4.runtime.CharStreams;
|
||||||
|
import org.antlr.v4.runtime.CommonTokenStream;
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTreeWalker;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
|
||||||
|
public class LogParserUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenLogContainsOneErrorLogEntry_thenOneErrorIsReturned() throws Exception {
|
||||||
|
String logLines = "2018-May-05 14:20:21 DEBUG entering awesome method\r\n" +
|
||||||
|
"2018-May-05 14:20:24 ERROR Bad thing happened\r\n";
|
||||||
|
LogLexer serverLogLexer = new LogLexer(CharStreams.fromString(logLines));
|
||||||
|
CommonTokenStream tokens = new CommonTokenStream( serverLogLexer );
|
||||||
|
LogParser logParser = new LogParser(tokens);
|
||||||
|
ParseTreeWalker walker = new ParseTreeWalker();
|
||||||
|
LogListener logWalker = new LogListener();
|
||||||
|
walker.walk(logWalker, logParser.log());
|
||||||
|
|
||||||
|
assertThat(logWalker.getEntries().size(), is(2));
|
||||||
|
LogEntry error = logWalker.getEntries().get(1);
|
||||||
|
assertThat(error.getLevel(), is(LogLevel.ERROR));
|
||||||
|
assertThat(error.getMessage(), is("Bad thing happened"));
|
||||||
|
assertThat(error.getTimestamp(), is(LocalDateTime.of(2018,5,5,14,20,24)));
|
||||||
|
}
|
||||||
|
}
|
5
pom.xml
5
pom.xml
|
@ -266,8 +266,9 @@
|
||||||
<module>twilio</module>
|
<module>twilio</module>
|
||||||
<module>spring-boot-ctx-fluent</module>
|
<module>spring-boot-ctx-fluent</module>
|
||||||
<module>java-ee-8-security-api</module>
|
<module>java-ee-8-security-api</module>
|
||||||
<module>spring-webflux-amqp</module>
|
<module>spring-webflux-amqp</module>
|
||||||
<module>maven-archetype</module>
|
<module>antlr</module>
|
||||||
|
<module>maven-archetype</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
Loading…
Reference in New Issue