From 4e38494a7a39ac2b4cdd8f5603988a5200d2581f Mon Sep 17 00:00:00 2001 From: Tiago Requeijo Date: Tue, 12 May 2020 22:00:29 -0400 Subject: [PATCH 1/2] Added an ANTLR json parser to replace jackson for parameter parsing --- .../cobol/parser/antlr/ParserJson.scala | 125 +++++ .../co/absa/cobrix/cobol/parser/antlr/json.g4 | 77 +++ .../cobol/parser/antlr/jsonBaseVisitor.java | 109 ++++ .../cobrix/cobol/parser/antlr/jsonLexer.java | 171 ++++++ .../cobrix/cobol/parser/antlr/jsonParser.java | 519 ++++++++++++++++++ .../cobol/parser/antlr/jsonVisitor.java | 104 ++++ .../cobrix/cobol/parser/parse/JsonSpec.scala | 59 ++ 7 files changed, 1164 insertions(+) create mode 100644 cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/ParserJson.scala create mode 100644 cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/json.g4 create mode 100644 cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/jsonBaseVisitor.java create mode 100644 cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/jsonLexer.java create mode 100644 cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/jsonParser.java create mode 100644 cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/jsonVisitor.java create mode 100644 cobol-parser/src/test/scala/za/co/absa/cobrix/cobol/parser/parse/JsonSpec.scala diff --git a/cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/ParserJson.scala b/cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/ParserJson.scala new file mode 100644 index 000000000..9c336b877 --- /dev/null +++ b/cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/ParserJson.scala @@ -0,0 +1,125 @@ +/* + * Copyright 2018 ABSA Group Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package za.co.absa.cobrix.cobol.parser.antlr +import org.antlr.v4.runtime.{BailErrorStrategy, CharStreams, CommonTokenStream} + +import scala.collection.JavaConversions._ + + +class ParserJson { + def parse(text: String): Any = { + val visitor = new ParserJsonVisitor() + val charStream = CharStreams.fromString(text) + val lexer = new jsonLexer(charStream) + val tokens = new CommonTokenStream(lexer) + val parser = new jsonParser(tokens) + parser.setErrorHandler(new BailErrorStrategy()); + visitor.visit(parser.json()) + } + + def parseMap(text: String): Map[String, Any] = { + this.parse(text).asInstanceOf[Map[String, Any]] + } +} + + +class ParserJsonVisitor extends jsonBaseVisitor[Any] { + /** + * Visit a parse tree produced by {@link jsonParser#pair}. + * + * @param ctx the parse tree + * @return the visitor result + */ + override def visitPair(ctx: jsonParser.PairContext): Any = { + val key = ctx.STRING().getText + val value = this.visit(ctx.value) + (key.substring(1, key.length - 1), value) + } + + /** + * Visit a parse tree produced by the {@code value_string} + * labeled alternative in {@link jsonParser#value}. + * + * @param ctx the parse tree + * @return the visitor result + */ + override def visitValue_string(ctx: jsonParser.Value_stringContext): Any = { + val text = ctx.getText + text.substring(1, text.length - 1) + } + + /** + * Visit a parse tree produced by the {@code value_number} + * labeled alternative in {@link jsonParser#value}. + * + * @param ctx the parse tree + * @return the visitor result + */ + override def visitValue_number(ctx: jsonParser.Value_numberContext): Any = { + val text = ctx.getText + try { text.toInt } catch { case _: Throwable => text.toDouble } + } + + /** + * Visit a parse tree produced by the {@code value_obj} + * labeled alternative in {@link jsonParser#value}. + * + * @param ctx the parse tree + * @return the visitor result + */ + override def visitValue_obj(ctx: jsonParser.Value_objContext): Any = { + ctx.obj().pair().map(x => this.visit(x).asInstanceOf[(String, Any)]).toMap + } + + /** + * Visit a parse tree produced by the {@code value_array} + * labeled alternative in {@link jsonParser#value}. + * + * @param ctx the parse tree + * @return the visitor result + */ + override def visitValue_array(ctx: jsonParser.Value_arrayContext): Any = { + ctx.arr.value.map(x => this.visit(x)).toArray + } + + /** + * Visit a parse tree produced by the {@code value_true} + * labeled alternative in {@link jsonParser#value}. + * + * @param ctx the parse tree + * @return the visitor result + */ + override def visitValue_true(ctx: jsonParser.Value_trueContext): Any = true + + /** + * Visit a parse tree produced by the {@code value_false} + * labeled alternative in {@link jsonParser#value}. + * + * @param ctx the parse tree + * @return the visitor result + */ + override def visitValue_false(ctx: jsonParser.Value_falseContext): Any = false + + /** + * Visit a parse tree produced by the {@code value_null} + * labeled alternative in {@link jsonParser#value}. + * + * @param ctx the parse tree + * @return the visitor result + */ + override def visitValue_null(ctx: jsonParser.Value_nullContext): Any = null +} diff --git a/cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/json.g4 b/cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/json.g4 new file mode 100644 index 000000000..b8abf0050 --- /dev/null +++ b/cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/json.g4 @@ -0,0 +1,77 @@ + +grammar json; + +json + : value + ; + +obj + : '{' pair (',' pair)* '}' + | '{' '}' + ; + +pair + : STRING ':' value + ; + +arr + : '[' value (',' value)* ']' + | '[' ']' + ; + +value + : STRING #value_string + | NUMBER #value_number + | obj #value_obj + | arr #value_array + | 'true' #value_true + | 'false' #value_false + | 'null' #value_null + ; + + +STRING + : '"' (ESC | SAFECODEPOINT)* '"' + ; + + +fragment ESC + : '\\' (["\\/bfnrt] | UNICODE) + ; + + +fragment UNICODE + : 'u' HEX HEX HEX HEX + ; + + +fragment HEX + : [0-9a-fA-F] + ; + + +fragment SAFECODEPOINT + : ~ ["\\\u0000-\u001F] + ; + + +NUMBER + : '-'? INT ('.' [0-9] +)? EXP? + ; + + +fragment INT + : '0' | [1-9] [0-9]* + ; + +// no leading zeros + +fragment EXP + : [Ee] [+\-]? INT + ; + +// \- since - means "range" inside [...] + +WS + : [ \t\n\r] + -> skip + ; \ No newline at end of file diff --git a/cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/jsonBaseVisitor.java b/cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/jsonBaseVisitor.java new file mode 100644 index 000000000..37ccad1b7 --- /dev/null +++ b/cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/jsonBaseVisitor.java @@ -0,0 +1,109 @@ +/* + * Copyright 2018 ABSA Group Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package za.co.absa.cobrix.cobol.parser.antlr; + +// Generated from json.g4 by ANTLR 4.7.2 +import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor; + +/** + * This class provides an empty implementation of {@link jsonVisitor}, + * which can be extended to create a visitor which only needs to handle a subset + * of the available methods. + * + * @param The return type of the visit operation. Use {@link Void} for + * operations with no return type. + */ +public class jsonBaseVisitor extends AbstractParseTreeVisitor implements jsonVisitor { + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitJson(jsonParser.JsonContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitObj(jsonParser.ObjContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitPair(jsonParser.PairContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitArr(jsonParser.ArrContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitValue_string(jsonParser.Value_stringContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitValue_number(jsonParser.Value_numberContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitValue_obj(jsonParser.Value_objContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitValue_array(jsonParser.Value_arrayContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitValue_true(jsonParser.Value_trueContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitValue_false(jsonParser.Value_falseContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitValue_null(jsonParser.Value_nullContext ctx) { return visitChildren(ctx); } +} diff --git a/cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/jsonLexer.java b/cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/jsonLexer.java new file mode 100644 index 000000000..2b0891da3 --- /dev/null +++ b/cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/jsonLexer.java @@ -0,0 +1,171 @@ +/* + * Copyright 2018 ABSA Group Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package za.co.absa.cobrix.cobol.parser.antlr; + +// Generated from json.g4 by ANTLR 4.7.2 +import org.antlr.v4.runtime.Lexer; +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.TokenStream; +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.atn.*; +import org.antlr.v4.runtime.dfa.DFA; +import org.antlr.v4.runtime.misc.*; + +@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) +public class jsonLexer extends Lexer { + static { RuntimeMetaData.checkVersion("4.7.2", RuntimeMetaData.VERSION); } + + protected static final DFA[] _decisionToDFA; + protected static final PredictionContextCache _sharedContextCache = + new PredictionContextCache(); + public static final int + T__0=1, T__1=2, T__2=3, T__3=4, T__4=5, T__5=6, T__6=7, T__7=8, T__8=9, + STRING=10, NUMBER=11, WS=12; + public static String[] channelNames = { + "DEFAULT_TOKEN_CHANNEL", "HIDDEN" + }; + + public static String[] modeNames = { + "DEFAULT_MODE" + }; + + private static String[] makeRuleNames() { + return new String[] { + "T__0", "T__1", "T__2", "T__3", "T__4", "T__5", "T__6", "T__7", "T__8", + "STRING", "ESC", "UNICODE", "HEX", "SAFECODEPOINT", "NUMBER", "INT", + "EXP", "WS" + }; + } + public static final String[] ruleNames = makeRuleNames(); + + private static String[] makeLiteralNames() { + return new String[] { + null, "'{'", "','", "'}'", "':'", "'['", "']'", "'true'", "'false'", + "'null'" + }; + } + private static final String[] _LITERAL_NAMES = makeLiteralNames(); + private static String[] makeSymbolicNames() { + return new String[] { + null, null, null, null, null, null, null, null, null, null, "STRING", + "NUMBER", "WS" + }; + } + private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); + public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); + + /** + * @deprecated Use {@link #VOCABULARY} instead. + */ + @Deprecated + public static final String[] tokenNames; + static { + tokenNames = new String[_SYMBOLIC_NAMES.length]; + for (int i = 0; i < tokenNames.length; i++) { + tokenNames[i] = VOCABULARY.getLiteralName(i); + if (tokenNames[i] == null) { + tokenNames[i] = VOCABULARY.getSymbolicName(i); + } + + if (tokenNames[i] == null) { + tokenNames[i] = ""; + } + } + } + + @Override + @Deprecated + public String[] getTokenNames() { + return tokenNames; + } + + @Override + + public Vocabulary getVocabulary() { + return VOCABULARY; + } + + + public jsonLexer(CharStream input) { + super(input); + _interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache); + } + + @Override + public String getGrammarFileName() { return "json.g4"; } + + @Override + public String[] getRuleNames() { return ruleNames; } + + @Override + public String getSerializedATN() { return _serializedATN; } + + @Override + public String[] getChannelNames() { return channelNames; } + + @Override + public String[] getModeNames() { return modeNames; } + + @Override + public ATN getATN() { return _ATN; } + + public static final String _serializedATN = + "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\16\u0082\b\1\4\2"+ + "\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4"+ + "\13\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22"+ + "\t\22\4\23\t\23\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\6\3\6\3\7\3\7\3\b\3"+ + "\b\3\b\3\b\3\b\3\t\3\t\3\t\3\t\3\t\3\t\3\n\3\n\3\n\3\n\3\n\3\13\3\13\3"+ + "\13\7\13G\n\13\f\13\16\13J\13\13\3\13\3\13\3\f\3\f\3\f\5\fQ\n\f\3\r\3"+ + "\r\3\r\3\r\3\r\3\r\3\16\3\16\3\17\3\17\3\20\5\20^\n\20\3\20\3\20\3\20"+ + "\6\20c\n\20\r\20\16\20d\5\20g\n\20\3\20\5\20j\n\20\3\21\3\21\3\21\7\21"+ + "o\n\21\f\21\16\21r\13\21\5\21t\n\21\3\22\3\22\5\22x\n\22\3\22\3\22\3\23"+ + "\6\23}\n\23\r\23\16\23~\3\23\3\23\2\2\24\3\3\5\4\7\5\t\6\13\7\r\b\17\t"+ + "\21\n\23\13\25\f\27\2\31\2\33\2\35\2\37\r!\2#\2%\16\3\2\n\n\2$$\61\61"+ + "^^ddhhppttvv\5\2\62;CHch\5\2\2!$$^^\3\2\62;\3\2\63;\4\2GGgg\4\2--//\5"+ + "\2\13\f\17\17\"\"\2\u0086\2\3\3\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2"+ + "\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2"+ + "\25\3\2\2\2\2\37\3\2\2\2\2%\3\2\2\2\3\'\3\2\2\2\5)\3\2\2\2\7+\3\2\2\2"+ + "\t-\3\2\2\2\13/\3\2\2\2\r\61\3\2\2\2\17\63\3\2\2\2\218\3\2\2\2\23>\3\2"+ + "\2\2\25C\3\2\2\2\27M\3\2\2\2\31R\3\2\2\2\33X\3\2\2\2\35Z\3\2\2\2\37]\3"+ + "\2\2\2!s\3\2\2\2#u\3\2\2\2%|\3\2\2\2\'(\7}\2\2(\4\3\2\2\2)*\7.\2\2*\6"+ + "\3\2\2\2+,\7\177\2\2,\b\3\2\2\2-.\7<\2\2.\n\3\2\2\2/\60\7]\2\2\60\f\3"+ + "\2\2\2\61\62\7_\2\2\62\16\3\2\2\2\63\64\7v\2\2\64\65\7t\2\2\65\66\7w\2"+ + "\2\66\67\7g\2\2\67\20\3\2\2\289\7h\2\29:\7c\2\2:;\7n\2\2;<\7u\2\2<=\7"+ + "g\2\2=\22\3\2\2\2>?\7p\2\2?@\7w\2\2@A\7n\2\2AB\7n\2\2B\24\3\2\2\2CH\7"+ + "$\2\2DG\5\27\f\2EG\5\35\17\2FD\3\2\2\2FE\3\2\2\2GJ\3\2\2\2HF\3\2\2\2H"+ + "I\3\2\2\2IK\3\2\2\2JH\3\2\2\2KL\7$\2\2L\26\3\2\2\2MP\7^\2\2NQ\t\2\2\2"+ + "OQ\5\31\r\2PN\3\2\2\2PO\3\2\2\2Q\30\3\2\2\2RS\7w\2\2ST\5\33\16\2TU\5\33"+ + "\16\2UV\5\33\16\2VW\5\33\16\2W\32\3\2\2\2XY\t\3\2\2Y\34\3\2\2\2Z[\n\4"+ + "\2\2[\36\3\2\2\2\\^\7/\2\2]\\\3\2\2\2]^\3\2\2\2^_\3\2\2\2_f\5!\21\2`b"+ + "\7\60\2\2ac\t\5\2\2ba\3\2\2\2cd\3\2\2\2db\3\2\2\2de\3\2\2\2eg\3\2\2\2"+ + "f`\3\2\2\2fg\3\2\2\2gi\3\2\2\2hj\5#\22\2ih\3\2\2\2ij\3\2\2\2j \3\2\2\2"+ + "kt\7\62\2\2lp\t\6\2\2mo\t\5\2\2nm\3\2\2\2or\3\2\2\2pn\3\2\2\2pq\3\2\2"+ + "\2qt\3\2\2\2rp\3\2\2\2sk\3\2\2\2sl\3\2\2\2t\"\3\2\2\2uw\t\7\2\2vx\t\b"+ + "\2\2wv\3\2\2\2wx\3\2\2\2xy\3\2\2\2yz\5!\21\2z$\3\2\2\2{}\t\t\2\2|{\3\2"+ + "\2\2}~\3\2\2\2~|\3\2\2\2~\177\3\2\2\2\177\u0080\3\2\2\2\u0080\u0081\b"+ + "\23\2\2\u0081&\3\2\2\2\16\2FHP]dfipsw~\3\b\2\2"; + public static final ATN _ATN = + new ATNDeserializer().deserialize(_serializedATN.toCharArray()); + static { + _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()]; + for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) { + _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i); + } + } +} diff --git a/cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/jsonParser.java b/cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/jsonParser.java new file mode 100644 index 000000000..c86f3a197 --- /dev/null +++ b/cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/jsonParser.java @@ -0,0 +1,519 @@ +/* + * Copyright 2018 ABSA Group Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package za.co.absa.cobrix.cobol.parser.antlr; + +// Generated from json.g4 by ANTLR 4.7.2 +import org.antlr.v4.runtime.atn.*; +import org.antlr.v4.runtime.dfa.DFA; +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.misc.*; +import org.antlr.v4.runtime.tree.*; +import java.util.List; +import java.util.Iterator; +import java.util.ArrayList; + +@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) +public class jsonParser extends Parser { + static { RuntimeMetaData.checkVersion("4.7.2", RuntimeMetaData.VERSION); } + + protected static final DFA[] _decisionToDFA; + protected static final PredictionContextCache _sharedContextCache = + new PredictionContextCache(); + public static final int + T__0=1, T__1=2, T__2=3, T__3=4, T__4=5, T__5=6, T__6=7, T__7=8, T__8=9, + STRING=10, NUMBER=11, WS=12; + public static final int + RULE_json = 0, RULE_obj = 1, RULE_pair = 2, RULE_arr = 3, RULE_value = 4; + private static String[] makeRuleNames() { + return new String[] { + "json", "obj", "pair", "arr", "value" + }; + } + public static final String[] ruleNames = makeRuleNames(); + + private static String[] makeLiteralNames() { + return new String[] { + null, "'{'", "','", "'}'", "':'", "'['", "']'", "'true'", "'false'", + "'null'" + }; + } + private static final String[] _LITERAL_NAMES = makeLiteralNames(); + private static String[] makeSymbolicNames() { + return new String[] { + null, null, null, null, null, null, null, null, null, null, "STRING", + "NUMBER", "WS" + }; + } + private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); + public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); + + /** + * @deprecated Use {@link #VOCABULARY} instead. + */ + @Deprecated + public static final String[] tokenNames; + static { + tokenNames = new String[_SYMBOLIC_NAMES.length]; + for (int i = 0; i < tokenNames.length; i++) { + tokenNames[i] = VOCABULARY.getLiteralName(i); + if (tokenNames[i] == null) { + tokenNames[i] = VOCABULARY.getSymbolicName(i); + } + + if (tokenNames[i] == null) { + tokenNames[i] = ""; + } + } + } + + @Override + @Deprecated + public String[] getTokenNames() { + return tokenNames; + } + + @Override + + public Vocabulary getVocabulary() { + return VOCABULARY; + } + + @Override + public String getGrammarFileName() { return "json.g4"; } + + @Override + public String[] getRuleNames() { return ruleNames; } + + @Override + public String getSerializedATN() { return _serializedATN; } + + @Override + public ATN getATN() { return _ATN; } + + public jsonParser(TokenStream input) { + super(input); + _interp = new ParserATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache); + } + + public static class JsonContext extends ParserRuleContext { + public ValueContext value() { + return getRuleContext(ValueContext.class,0); + } + public JsonContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_json; } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof jsonVisitor ) return ((jsonVisitor)visitor).visitJson(this); + else return visitor.visitChildren(this); + } + } + + public final JsonContext json() throws RecognitionException { + JsonContext _localctx = new JsonContext(_ctx, getState()); + enterRule(_localctx, 0, RULE_json); + try { + enterOuterAlt(_localctx, 1); + { + setState(10); + value(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ObjContext extends ParserRuleContext { + public List pair() { + return getRuleContexts(PairContext.class); + } + public PairContext pair(int i) { + return getRuleContext(PairContext.class,i); + } + public ObjContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_obj; } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof jsonVisitor ) return ((jsonVisitor)visitor).visitObj(this); + else return visitor.visitChildren(this); + } + } + + public final ObjContext obj() throws RecognitionException { + ObjContext _localctx = new ObjContext(_ctx, getState()); + enterRule(_localctx, 2, RULE_obj); + int _la; + try { + setState(25); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,1,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); + { + setState(12); + match(T__0); + setState(13); + pair(); + setState(18); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==T__1) { + { + { + setState(14); + match(T__1); + setState(15); + pair(); + } + } + setState(20); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(21); + match(T__2); + } + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(23); + match(T__0); + setState(24); + match(T__2); + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class PairContext extends ParserRuleContext { + public TerminalNode STRING() { return getToken(jsonParser.STRING, 0); } + public ValueContext value() { + return getRuleContext(ValueContext.class,0); + } + public PairContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_pair; } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof jsonVisitor ) return ((jsonVisitor)visitor).visitPair(this); + else return visitor.visitChildren(this); + } + } + + public final PairContext pair() throws RecognitionException { + PairContext _localctx = new PairContext(_ctx, getState()); + enterRule(_localctx, 4, RULE_pair); + try { + enterOuterAlt(_localctx, 1); + { + setState(27); + match(STRING); + setState(28); + match(T__3); + setState(29); + value(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ArrContext extends ParserRuleContext { + public List value() { + return getRuleContexts(ValueContext.class); + } + public ValueContext value(int i) { + return getRuleContext(ValueContext.class,i); + } + public ArrContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_arr; } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof jsonVisitor ) return ((jsonVisitor)visitor).visitArr(this); + else return visitor.visitChildren(this); + } + } + + public final ArrContext arr() throws RecognitionException { + ArrContext _localctx = new ArrContext(_ctx, getState()); + enterRule(_localctx, 6, RULE_arr); + int _la; + try { + setState(44); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,3,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); + { + setState(31); + match(T__4); + setState(32); + value(); + setState(37); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==T__1) { + { + { + setState(33); + match(T__1); + setState(34); + value(); + } + } + setState(39); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(40); + match(T__5); + } + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(42); + match(T__4); + setState(43); + match(T__5); + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ValueContext extends ParserRuleContext { + public ValueContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_value; } + + public ValueContext() { } + public void copyFrom(ValueContext ctx) { + super.copyFrom(ctx); + } + } + public static class Value_trueContext extends ValueContext { + public Value_trueContext(ValueContext ctx) { copyFrom(ctx); } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof jsonVisitor ) return ((jsonVisitor)visitor).visitValue_true(this); + else return visitor.visitChildren(this); + } + } + public static class Value_falseContext extends ValueContext { + public Value_falseContext(ValueContext ctx) { copyFrom(ctx); } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof jsonVisitor ) return ((jsonVisitor)visitor).visitValue_false(this); + else return visitor.visitChildren(this); + } + } + public static class Value_stringContext extends ValueContext { + public TerminalNode STRING() { return getToken(jsonParser.STRING, 0); } + public Value_stringContext(ValueContext ctx) { copyFrom(ctx); } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof jsonVisitor ) return ((jsonVisitor)visitor).visitValue_string(this); + else return visitor.visitChildren(this); + } + } + public static class Value_objContext extends ValueContext { + public ObjContext obj() { + return getRuleContext(ObjContext.class,0); + } + public Value_objContext(ValueContext ctx) { copyFrom(ctx); } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof jsonVisitor ) return ((jsonVisitor)visitor).visitValue_obj(this); + else return visitor.visitChildren(this); + } + } + public static class Value_numberContext extends ValueContext { + public TerminalNode NUMBER() { return getToken(jsonParser.NUMBER, 0); } + public Value_numberContext(ValueContext ctx) { copyFrom(ctx); } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof jsonVisitor ) return ((jsonVisitor)visitor).visitValue_number(this); + else return visitor.visitChildren(this); + } + } + public static class Value_nullContext extends ValueContext { + public Value_nullContext(ValueContext ctx) { copyFrom(ctx); } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof jsonVisitor ) return ((jsonVisitor)visitor).visitValue_null(this); + else return visitor.visitChildren(this); + } + } + public static class Value_arrayContext extends ValueContext { + public ArrContext arr() { + return getRuleContext(ArrContext.class,0); + } + public Value_arrayContext(ValueContext ctx) { copyFrom(ctx); } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof jsonVisitor ) return ((jsonVisitor)visitor).visitValue_array(this); + else return visitor.visitChildren(this); + } + } + + public final ValueContext value() throws RecognitionException { + ValueContext _localctx = new ValueContext(_ctx, getState()); + enterRule(_localctx, 8, RULE_value); + try { + setState(53); + _errHandler.sync(this); + switch (_input.LA(1)) { + case STRING: + _localctx = new Value_stringContext(_localctx); + enterOuterAlt(_localctx, 1); + { + setState(46); + match(STRING); + } + break; + case NUMBER: + _localctx = new Value_numberContext(_localctx); + enterOuterAlt(_localctx, 2); + { + setState(47); + match(NUMBER); + } + break; + case T__0: + _localctx = new Value_objContext(_localctx); + enterOuterAlt(_localctx, 3); + { + setState(48); + obj(); + } + break; + case T__4: + _localctx = new Value_arrayContext(_localctx); + enterOuterAlt(_localctx, 4); + { + setState(49); + arr(); + } + break; + case T__6: + _localctx = new Value_trueContext(_localctx); + enterOuterAlt(_localctx, 5); + { + setState(50); + match(T__6); + } + break; + case T__7: + _localctx = new Value_falseContext(_localctx); + enterOuterAlt(_localctx, 6); + { + setState(51); + match(T__7); + } + break; + case T__8: + _localctx = new Value_nullContext(_localctx); + enterOuterAlt(_localctx, 7); + { + setState(52); + match(T__8); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static final String _serializedATN = + "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\16:\4\2\t\2\4\3\t"+ + "\3\4\4\t\4\4\5\t\5\4\6\t\6\3\2\3\2\3\3\3\3\3\3\3\3\7\3\23\n\3\f\3\16\3"+ + "\26\13\3\3\3\3\3\3\3\3\3\5\3\34\n\3\3\4\3\4\3\4\3\4\3\5\3\5\3\5\3\5\7"+ + "\5&\n\5\f\5\16\5)\13\5\3\5\3\5\3\5\3\5\5\5/\n\5\3\6\3\6\3\6\3\6\3\6\3"+ + "\6\3\6\5\68\n\6\3\6\2\2\7\2\4\6\b\n\2\2\2>\2\f\3\2\2\2\4\33\3\2\2\2\6"+ + "\35\3\2\2\2\b.\3\2\2\2\n\67\3\2\2\2\f\r\5\n\6\2\r\3\3\2\2\2\16\17\7\3"+ + "\2\2\17\24\5\6\4\2\20\21\7\4\2\2\21\23\5\6\4\2\22\20\3\2\2\2\23\26\3\2"+ + "\2\2\24\22\3\2\2\2\24\25\3\2\2\2\25\27\3\2\2\2\26\24\3\2\2\2\27\30\7\5"+ + "\2\2\30\34\3\2\2\2\31\32\7\3\2\2\32\34\7\5\2\2\33\16\3\2\2\2\33\31\3\2"+ + "\2\2\34\5\3\2\2\2\35\36\7\f\2\2\36\37\7\6\2\2\37 \5\n\6\2 \7\3\2\2\2!"+ + "\"\7\7\2\2\"\'\5\n\6\2#$\7\4\2\2$&\5\n\6\2%#\3\2\2\2&)\3\2\2\2\'%\3\2"+ + "\2\2\'(\3\2\2\2(*\3\2\2\2)\'\3\2\2\2*+\7\b\2\2+/\3\2\2\2,-\7\7\2\2-/\7"+ + "\b\2\2.!\3\2\2\2.,\3\2\2\2/\t\3\2\2\2\608\7\f\2\2\618\7\r\2\2\628\5\4"+ + "\3\2\638\5\b\5\2\648\7\t\2\2\658\7\n\2\2\668\7\13\2\2\67\60\3\2\2\2\67"+ + "\61\3\2\2\2\67\62\3\2\2\2\67\63\3\2\2\2\67\64\3\2\2\2\67\65\3\2\2\2\67"+ + "\66\3\2\2\28\13\3\2\2\2\7\24\33\'.\67"; + public static final ATN _ATN = + new ATNDeserializer().deserialize(_serializedATN.toCharArray()); + static { + _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()]; + for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) { + _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i); + } + } +} diff --git a/cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/jsonVisitor.java b/cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/jsonVisitor.java new file mode 100644 index 000000000..9046c4eb0 --- /dev/null +++ b/cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/antlr/jsonVisitor.java @@ -0,0 +1,104 @@ +/* + * Copyright 2018 ABSA Group Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package za.co.absa.cobrix.cobol.parser.antlr; + +// Generated from json.g4 by ANTLR 4.7.2 +import org.antlr.v4.runtime.tree.ParseTreeVisitor; + +/** + * This interface defines a complete generic visitor for a parse tree produced + * by {@link jsonParser}. + * + * @param The return type of the visit operation. Use {@link Void} for + * operations with no return type. + */ +public interface jsonVisitor extends ParseTreeVisitor { + /** + * Visit a parse tree produced by {@link jsonParser#json}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitJson(jsonParser.JsonContext ctx); + /** + * Visit a parse tree produced by {@link jsonParser#obj}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitObj(jsonParser.ObjContext ctx); + /** + * Visit a parse tree produced by {@link jsonParser#pair}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitPair(jsonParser.PairContext ctx); + /** + * Visit a parse tree produced by {@link jsonParser#arr}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitArr(jsonParser.ArrContext ctx); + /** + * Visit a parse tree produced by the {@code value_string} + * labeled alternative in {@link jsonParser#value}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitValue_string(jsonParser.Value_stringContext ctx); + /** + * Visit a parse tree produced by the {@code value_number} + * labeled alternative in {@link jsonParser#value}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitValue_number(jsonParser.Value_numberContext ctx); + /** + * Visit a parse tree produced by the {@code value_obj} + * labeled alternative in {@link jsonParser#value}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitValue_obj(jsonParser.Value_objContext ctx); + /** + * Visit a parse tree produced by the {@code value_array} + * labeled alternative in {@link jsonParser#value}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitValue_array(jsonParser.Value_arrayContext ctx); + /** + * Visit a parse tree produced by the {@code value_true} + * labeled alternative in {@link jsonParser#value}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitValue_true(jsonParser.Value_trueContext ctx); + /** + * Visit a parse tree produced by the {@code value_false} + * labeled alternative in {@link jsonParser#value}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitValue_false(jsonParser.Value_falseContext ctx); + /** + * Visit a parse tree produced by the {@code value_null} + * labeled alternative in {@link jsonParser#value}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitValue_null(jsonParser.Value_nullContext ctx); +} diff --git a/cobol-parser/src/test/scala/za/co/absa/cobrix/cobol/parser/parse/JsonSpec.scala b/cobol-parser/src/test/scala/za/co/absa/cobrix/cobol/parser/parse/JsonSpec.scala new file mode 100644 index 000000000..03c7f7018 --- /dev/null +++ b/cobol-parser/src/test/scala/za/co/absa/cobrix/cobol/parser/parse/JsonSpec.scala @@ -0,0 +1,59 @@ +/* + * Copyright 2018 ABSA Group Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package za.co.absa.cobrix.cobol.parser.parse + +import org.antlr.v4.runtime.misc.ParseCancellationException +import org.scalatest.FunSuite +import za.co.absa.cobrix.cobol.parser.antlr.{ParserJson} + + +class JsonSpec extends FunSuite { + val parser = new ParserJson() + def parse(text: String) = parser.parse(text) + + + test("Test JSON") { + // literals + assert(parse("null") == null) + assert(parse("false") == false) + assert(parse("true") == true) + // numbers + assert(parse("1.2") == 1.2) + assert(parse("5") == 5) + assert(parse("5").isInstanceOf[Int]) + assert(parse("5.0").isInstanceOf[Double]) + // strings + assert(parse("\"ABC\"") == "ABC") + assert(parse("\"1.2\"") == "1.2") + assert(parse("\"5\"") == "5") + // arrays + assert(parse("[\"ABC\", 1, 2]").asInstanceOf[Array[Any]].deep == Array("ABC", 1.0, 2.0).deep) + // maps + assert(parse("{\"ABC\": 1.2}") == Map("ABC" -> 1.2)) + // as map + assert(parser.parseMap("{\"ABC\": 1.2}") == Map("ABC" -> 1.2)) + } + + test("JSON Fails") { + // syntax + intercept[ParseCancellationException] { parse("\"ABC") } + intercept[ParseCancellationException] { parse("{\"ABC\": abc}") } + intercept[ParseCancellationException] { parse("{\"ABC\"= 1}") } + // cast to map + intercept[ClassCastException] { parser.parseMap("1.2") } + } +} From 70b672c7727d289eb995580f223f4aa3e237d4df Mon Sep 17 00:00:00 2001 From: Tiago Requeijo Date: Tue, 12 May 2020 22:24:50 -0400 Subject: [PATCH 2/2] Swithc spark-cobol to the new json parser --- project/Dependencies.scala | 2 -- spark-cobol/pom.xml | 9 --------- .../cobol/parameters/CobolParametersParser.scala | 11 ++++------- .../source/integration/Test25OccursMappings.scala | 5 ++--- 4 files changed, 6 insertions(+), 21 deletions(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 3ed709488..2fd721403 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -46,8 +46,6 @@ object Dependencies { // version of Guava which has removed 'com.google.common.base.Stopwatch.elapsedMillis', // however, the version of Hadoop imported by Spark relies on that method. "com.google.guava" % "guava" % guavaVersion, - // Make sure the jackson dependency doesn't conflict with Spark's - "com.fasterxml.jackson.module" %% "jackson-module-scala" % jacksonVersion ) val CobolParserDependencies: Seq[ModuleID] = Seq( diff --git a/spark-cobol/pom.xml b/spark-cobol/pom.xml index dfec40b4e..8d3707b9e 100644 --- a/spark-cobol/pom.xml +++ b/spark-cobol/pom.xml @@ -56,15 +56,6 @@ guava - - - - - - - - za.co.absa.cobrix diff --git a/spark-cobol/src/main/scala/za/co/absa/cobrix/spark/cobol/parameters/CobolParametersParser.scala b/spark-cobol/src/main/scala/za/co/absa/cobrix/spark/cobol/parameters/CobolParametersParser.scala index 077b91eaa..cd4dcac74 100644 --- a/spark-cobol/src/main/scala/za/co/absa/cobrix/spark/cobol/parameters/CobolParametersParser.scala +++ b/spark-cobol/src/main/scala/za/co/absa/cobrix/spark/cobol/parameters/CobolParametersParser.scala @@ -16,11 +16,9 @@ package za.co.absa.cobrix.spark.cobol.parameters -import com.fasterxml.jackson.databind.{DeserializationFeature, ObjectMapper} -import com.fasterxml.jackson.module.scala.DefaultScalaModule -import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper import org.slf4j.LoggerFactory import za.co.absa.cobrix.cobol.parser.CopybookParser +import za.co.absa.cobrix.cobol.parser.antlr.ParserJson import za.co.absa.cobrix.cobol.parser.decoders.FloatingPointFormat import za.co.absa.cobrix.cobol.parser.decoders.FloatingPointFormat.FloatingPointFormat import za.co.absa.cobrix.cobol.parser.policies.StringTrimmingPolicy.StringTrimmingPolicy @@ -494,9 +492,8 @@ object CobolParametersParser { */ @throws(classOf[IllegalArgumentException]) def getOccursMappings(params: String): Map[String, Map[String, Int]] = { - val mapper = new ObjectMapper() with ScalaObjectMapper - mapper.registerModule(DefaultScalaModule) - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - mapper.readValue[Map[String,Map[String,Int]]](params) + val parser = new ParserJson() + val parsedParams = parser.parseMap(params) + parsedParams.map( kv => kv._1 -> kv._2.asInstanceOf[Map[String, Any]].map(x => x._1 -> x._2.asInstanceOf[Int])) } } \ No newline at end of file diff --git a/spark-cobol/src/test/scala/za/co/absa/cobrix/spark/cobol/source/integration/Test25OccursMappings.scala b/spark-cobol/src/test/scala/za/co/absa/cobrix/spark/cobol/source/integration/Test25OccursMappings.scala index cd85ddab1..2e3554997 100644 --- a/spark-cobol/src/test/scala/za/co/absa/cobrix/spark/cobol/source/integration/Test25OccursMappings.scala +++ b/spark-cobol/src/test/scala/za/co/absa/cobrix/spark/cobol/source/integration/Test25OccursMappings.scala @@ -19,7 +19,6 @@ package za.co.absa.cobrix.spark.cobol.source.integration import java.nio.charset.StandardCharsets import java.nio.file.{Files, Paths} -import com.fasterxml.jackson.databind.exc.InvalidFormatException import org.scalatest.FunSuite import za.co.absa.cobrix.cobol.parser.CopybookParser import za.co.absa.cobrix.cobol.parser.decoders.FloatingPointFormat @@ -91,7 +90,7 @@ class Test25OccursMappings extends FunSuite with SparkTestBase { } test("Integration test fail on bad occurs mappings") { - val exc = intercept[InvalidFormatException] { + val exc = intercept[ClassCastException] { spark .read .format("cobol") @@ -101,7 +100,7 @@ class Test25OccursMappings extends FunSuite with SparkTestBase { .option("variable_size_occurs", "true") .load(inputDataPath + "/data.dat") } - assert(exc.getMessage.contains("not a valid Integer value")) + assert(exc.getMessage.contains("java.lang.Double cannot be cast to java.lang.Integer")) } test(s"Integration test on $exampleName data for variable occurs") {