I am building a small Java utility (using Jackson) to catch errors in Java files, and one part of it is a text area, in which you might paste some JSON context and it will tell you the line and column where it’s found it:
I am using the error message to take out the line and column as a string and print it out in the interface for someone using it.
This is the JSON sample I’m working with, and there is an intentional error beside “age”, where it’s missing a colon:
{ "name": "mkyong.com", "messages": ["msg 1", "msg 2", "msg 3"], "age" 100 }
What I want to do is also highlight the problematic area in a cyan color, and for that purpose, I have this code for the button that validates what’s inserted in the text area:
cmdValidate.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { functionsClass ops = new functionsClass(); String JSONcontent = JSONtextArea.getText(); Results obj = new Results(); ops.validate_JSON_text(JSONcontent, obj); String result = obj.getResult(); String caret = obj.getCaret(); //String lineNum = obj.getLineNum(); //showStatus(result); if(result==null) { textAreaError.setText("JSON code is valid!"); } else { textAreaError.setText(result); Highlighter.HighlightPainter cyanPainter; cyanPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.cyan); int caretPosition = Integer.parseInt(caret); int lineNumber = 0; try { lineNumber = JSONtextArea.getLineOfOffset(caretPosition); } catch (BadLocationException e2) { // TODO Auto-generated catch block e2.printStackTrace(); } try { JSONtextArea.getHighlighter().addHighlight(lineNumber, caretPosition + 1, cyanPainter); } catch (BadLocationException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } } }); }
The “addHighlight” method works with a start range, end range and a color, which didn’t become apparent to me immediately, thinking I had to get the reference line based on the column number. Some split functions to extract the numbers, I assigned 11 (in screenshot) to a caret value, not realizing that it only counts character positions from the beginning of the string and represents the end point of the range.
For reference, this is the class that does the work behind the scenes, and the error handling at the bottom is about extracting the line and column numbers. For the record, “x” is the error message that would generate out of an invalid file.
package parsingJSON; import java.io.IOException; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; public class functionsClass extends JSONTextCompare { public boolean validate_JSON_text(String JSONcontent, Results obj) { boolean valid = false; try { ObjectMapper objMapper = new ObjectMapper(); JsonNode validation = objMapper.readTree(JSONcontent); valid = true; } catch (JsonParseException jpe){ String x = jpe.getMessage(); printTextArea(x, obj); //return part_3; } catch (IOException ioe) { String x = ioe.getMessage(); printTextArea(x, obj); //return part_3; } return valid; } public void printTextArea(String x, Results obj) { // TODO Auto-generated method stub System.out.println(x); String err = x.substring(x.lastIndexOf("n")); String parts[] = err.split(";"); //String part 1 is the discarded leading edge that is the closing brackets of the JSON content String part_2 = parts[1]; //split again to get rid of the closing square bracket String parts2[] = part_2.split("]"); String part_3 = parts2[0]; //JSONTextCompare feedback = new JSONTextCompare(); //split the output to get the exact location of the error to communicate back and highlight it in the JSONTextCompare class //first need to get the line number from the output String[] parts_lineNum = part_3.split("line: "); String[] parts_lineNum_final = parts_lineNum[1].split(", column:"); String lineNum = parts_lineNum_final[0]; String[] parts_caret = part_3.split("column: "); String caret = parts_caret[1]; System.out.println(caret); obj.setLineNum(lineNum); obj.setCaret(caret); obj.setResult(part_3); System.out.println(part_3); } }
Screenshot for what the interface currently looks like:
Long story short – how do I turn the coordinates Line 4, Col 11 into a caret value (e.g. it’s value 189, for the sake of argument) that I can use to get the highlighter to work properly. Some kind of custom parsing formula might be possible, but in general, is that even possible to do?
Advertisement
Answer
how do I turn the coordinates Line 4, Col 11 into a caret value (e.g. it’s value 189,
Check out: Text Utilities for methods that might be helpful when working with text components. It has methods like:
- centerLineInScrollPane
- getColumnAtCaret
- getLineAtCaret
- getLines
- gotoStartOfLine
- gotoFirstWordOnLine
- getWrappedLines
In particular the gotoStartOfLine()
method contains code you can modify to get the offset of the specified row/column.offset.
The basic code would be:
int line = 4; int column = 11; Element root = textArea.getDocument().getDefaultRootElement(); int offset = root.getElement( line - 1 ).getStartOffset() + column; System.out.println(offset);