mirror of https://github.com/apache/jmeter.git
Bug 42582 - JSON pretty printing in Tree View Listener
git-svn-id: https://svn.apache.org/repos/asf/jakarta/jmeter/branches/rel-2-2@545917 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
d32d1f709c
commit
e09e4965b0
|
|
@ -28,9 +28,12 @@ import java.awt.event.ActionListener;
|
|||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.Character;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.ButtonGroup;
|
||||
|
|
@ -116,6 +119,8 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
|
|||
|
||||
private static final String HTML_BUTTON_LABEL = "Render HTML";
|
||||
|
||||
private static final String JSON_BUTTON_LABEL = "Render JSON";
|
||||
|
||||
private static final String XML_BUTTON_LABEL = "Render XML";
|
||||
|
||||
private static final String TEXT_BUTTON_LABEL = "Show Text";
|
||||
|
|
@ -124,6 +129,8 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
|
|||
|
||||
private static final String HTML_COMMAND = "html"; // $NON-NLS-1$
|
||||
|
||||
private static final String JSON_COMMAND = "json"; // $NON-NLS-1$
|
||||
|
||||
private static final String XML_COMMAND = "xml"; // $NON-NLS-1$
|
||||
|
||||
private static final String TEXT_COMMAND = "text"; // $NON-NLS-1$
|
||||
|
|
@ -136,6 +143,19 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
|
|||
|
||||
private boolean textMode = true;
|
||||
|
||||
private static final String ESC_CHAR_REGEX = "\\\\[\"\\\\/bfnrt]|\\\\u[0-9A-Fa-f]{4}"; // $NON-NLS-1$
|
||||
|
||||
private static final String NORMAL_CHARACTER_REGEX = "[^\"\\\\]"; // $NON-NLS-1$
|
||||
|
||||
private static final String STRING_REGEX = "\"(" + ESC_CHAR_REGEX + "|" + NORMAL_CHARACTER_REGEX + ")*\""; // $NON-NLS-1$
|
||||
|
||||
// This 'other value' regex is deliberately weak, even accepting an empty string, to be useful when reporting malformed data.
|
||||
private static final String OTHER_VALUE_REGEX = "[^\\{\\[\\]\\}\\,]*"; // $NON-NLS-1$
|
||||
|
||||
private static final String VALUE_OR_PAIR_REGEX = "((" + STRING_REGEX + "\\s*:)?\\s*(" + STRING_REGEX + "|" + OTHER_VALUE_REGEX + ")\\s*,?\\s*)"; // $NON-NLS-1$
|
||||
|
||||
private static final Pattern VALUE_OR_PAIR_PATTERN = Pattern.compile(VALUE_OR_PAIR_REGEX);
|
||||
|
||||
// set default command to Text
|
||||
private String command = TEXT_COMMAND;
|
||||
|
||||
|
|
@ -166,6 +186,8 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
|
|||
|
||||
private JRadioButton htmlButton;
|
||||
|
||||
private JRadioButton jsonButton;
|
||||
|
||||
private JRadioButton xmlButton;
|
||||
|
||||
private JCheckBox downloadAll;
|
||||
|
|
@ -393,6 +415,8 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
|
|||
showTextResponse(response);
|
||||
} else if (command.equals(HTML_COMMAND)) {
|
||||
showRenderedResponse(response, res);
|
||||
} else if (command.equals(JSON_COMMAND)) {
|
||||
showRenderJSONResponse(response);
|
||||
} else if (command.equals(XML_COMMAND)) {
|
||||
showRenderXMLResponse(response);
|
||||
}
|
||||
|
|
@ -436,6 +460,7 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
|
|||
resultsScrollPane.setViewportView(imageLabel);
|
||||
textButton.setEnabled(false);
|
||||
htmlButton.setEnabled(false);
|
||||
jsonButton.setEnabled(false);
|
||||
xmlButton.setEnabled(false);
|
||||
}
|
||||
|
||||
|
|
@ -447,6 +472,74 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
|
|||
|
||||
textButton.setEnabled(true);
|
||||
htmlButton.setEnabled(true);
|
||||
jsonButton.setEnabled(true);
|
||||
xmlButton.setEnabled(true);
|
||||
}
|
||||
|
||||
// It might be useful also to make this available in the 'Request' tab, for
|
||||
// when posting JSON.
|
||||
private static String prettyJSON(String json) {
|
||||
StringBuffer pretty = new StringBuffer(json.length() * 2); // Educated guess
|
||||
|
||||
final String tab = ": "; // $NON-NLS-1$
|
||||
StringBuffer index = new StringBuffer();
|
||||
String nl = ""; // $NON-NLS-1$
|
||||
|
||||
Matcher valueOrPair = VALUE_OR_PAIR_PATTERN.matcher(json);
|
||||
|
||||
boolean misparse = false;
|
||||
|
||||
for (int i = 0; i < json.length(); ) {
|
||||
final char currentChar = json.charAt(i);
|
||||
if ((currentChar == '{') || (currentChar == '[')) {
|
||||
pretty.append(nl).append(index).append(currentChar);
|
||||
i++;
|
||||
index.append(tab);
|
||||
misparse = false;
|
||||
}
|
||||
else if ((currentChar == '}') || (currentChar == ']')) {
|
||||
if (index.length() > 0) {
|
||||
index.delete(0, tab.length());
|
||||
}
|
||||
pretty.append(nl).append(index).append(currentChar);
|
||||
i++;
|
||||
int j = i;
|
||||
while ((j < json.length()) && Character.isWhitespace(json.charAt(j))) {
|
||||
j++;
|
||||
}
|
||||
if ((j < json.length()) && (json.charAt(j) == ',')) {
|
||||
pretty.append(","); // $NON-NLS-1$
|
||||
i=j+1;
|
||||
}
|
||||
misparse = false;
|
||||
}
|
||||
else if (valueOrPair.find(i) && valueOrPair.group().length() > 0) {
|
||||
pretty.append(nl).append(index).append(valueOrPair.group());
|
||||
i=valueOrPair.end();
|
||||
misparse = false;
|
||||
}
|
||||
else {
|
||||
if (!misparse) {
|
||||
pretty.append(nl).append("- Parse failed from:");
|
||||
}
|
||||
pretty.append(currentChar);
|
||||
i++;
|
||||
misparse = true;
|
||||
}
|
||||
nl = "\n"; // $NON-NLS-1$
|
||||
}
|
||||
return pretty.toString();
|
||||
}
|
||||
|
||||
private void showRenderJSONResponse(String response) {
|
||||
results.setContentType("text/plain"); // $NON-NLS-1$
|
||||
results.setText(response == null ? "" : prettyJSON(response));
|
||||
results.setCaretPosition(0);
|
||||
resultsScrollPane.setViewportView(results);
|
||||
|
||||
textButton.setEnabled(true);
|
||||
htmlButton.setEnabled(true);
|
||||
jsonButton.setEnabled(true);
|
||||
xmlButton.setEnabled(true);
|
||||
}
|
||||
|
||||
|
|
@ -509,6 +602,7 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
|
|||
resultsScrollPane.setViewportView(view);
|
||||
textButton.setEnabled(true);
|
||||
htmlButton.setEnabled(true);
|
||||
jsonButton.setEnabled(true);
|
||||
xmlButton.setEnabled(true);
|
||||
}
|
||||
|
||||
|
|
@ -552,7 +646,8 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
|
|||
command = e.getActionCommand();
|
||||
|
||||
if (command != null
|
||||
&& (command.equals(TEXT_COMMAND) || command.equals(HTML_COMMAND) || command.equals(XML_COMMAND))) {
|
||||
&& (command.equals(TEXT_COMMAND) || command.equals(HTML_COMMAND)
|
||||
|| command.equals(JSON_COMMAND) || command.equals(XML_COMMAND))) {
|
||||
|
||||
textMode = command.equals(TEXT_COMMAND);
|
||||
|
||||
|
|
@ -570,6 +665,8 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
|
|||
showTextResponse(response);
|
||||
} else if (command.equals(HTML_COMMAND)) {
|
||||
showRenderedResponse(response, res);
|
||||
} else if (command.equals(JSON_COMMAND)) {
|
||||
showRenderJSONResponse(response);
|
||||
} else if (command.equals(XML_COMMAND)) {
|
||||
showRenderXMLResponse(response);
|
||||
}
|
||||
|
|
@ -627,6 +724,7 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
|
|||
|
||||
textButton.setEnabled(true);
|
||||
htmlButton.setEnabled(true);
|
||||
jsonButton.setEnabled(true);
|
||||
xmlButton.setEnabled(true);
|
||||
}
|
||||
|
||||
|
|
@ -645,6 +743,12 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
|
|||
htmlButton.setSelected(!textMode);
|
||||
group.add(htmlButton);
|
||||
|
||||
jsonButton = new JRadioButton(JSON_BUTTON_LABEL);
|
||||
jsonButton.setActionCommand(JSON_COMMAND);
|
||||
jsonButton.addActionListener(this);
|
||||
jsonButton.setSelected(!textMode);
|
||||
group.add(jsonButton);
|
||||
|
||||
xmlButton = new JRadioButton(XML_BUTTON_LABEL);
|
||||
xmlButton.setActionCommand(XML_COMMAND);
|
||||
xmlButton.addActionListener(this);
|
||||
|
|
@ -657,6 +761,7 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
|
|||
pane.add(textButton);
|
||||
pane.add(htmlButton);
|
||||
pane.add(xmlButton);
|
||||
pane.add(jsonButton);
|
||||
pane.add(downloadAll);
|
||||
return pane;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,6 +166,7 @@ Removed deprecated method JMeterUtils.split() - use JOrphanUtils version instead
|
|||
<li>Bug 41913 - TransactionController now creates samples as sub-samples of the transaction</li>
|
||||
<li>Bug 42506 - JMeter threads all use the same SSL session</li>
|
||||
<li>BeanShell elements now support ThreadListener and TestListener interfaces</li>
|
||||
<li>Bug 42582 - JSON pretty printing in Tree View Listener</li>
|
||||
</ul>
|
||||
|
||||
<h4>Non-functional improvements:</h4>
|
||||
|
|
|
|||
|
|
@ -1663,8 +1663,7 @@ this response, and some response codes.
|
|||
Note that the Request panel only shows the headers added by JMeter.
|
||||
It does not show any headers (such as Host) that may be added by the HTTP protocol implementation.
|
||||
<p>
|
||||
There are three ways to view the response, selectable by a radio
|
||||
button.</p>
|
||||
There are several ways to view the response, selectable by a radio button.</p>
|
||||
<p>The default view shows all of the text contained in the
|
||||
response.</p>
|
||||
<p>The HTML view attempts to render the response as
|
||||
|
|
@ -1678,6 +1677,7 @@ If the checkbox is not selected, the renderer will not download images etc.
|
|||
<p>The Render XML view will show response in tree style.
|
||||
Any DTD nodes or Prolog nodes will not show up in tree; however, response may contain those nodes.
|
||||
</p>
|
||||
<p>The Render JSON view will show the response in tree style (also handles JSON embedded in JavaScript).</p>
|
||||
</description>
|
||||
<p>
|
||||
The Control Panel (above) shows an example of an HTML display.
|
||||
|
|
|
|||
Loading…
Reference in New Issue