+ Add JsonToStringStyle implementation to ToStringStyleAdd NoClassNameToStringStyle implementation of ToStringStyleFix wrong examples in JavaDoc of StringUtils.replaceEachRepeatedly(...), StringUtils.replaceEach(...)Add StringUtils.containsAny(CharSequence, CharSequence...) method
diff --git a/src/main/java/org/apache/commons/lang3/builder/ToStringStyle.java b/src/main/java/org/apache/commons/lang3/builder/ToStringStyle.java
index 5bb7d35d2..24f295aae 100644
--- a/src/main/java/org/apache/commons/lang3/builder/ToStringStyle.java
+++ b/src/main/java/org/apache/commons/lang3/builder/ToStringStyle.java
@@ -139,6 +139,29 @@ public abstract class ToStringStyle implements Serializable {
*/
public static final ToStringStyle NO_CLASS_NAME_STYLE = new NoClassNameToStringStyle();
+ /**
+ * The JSON toString style. Using the Person example from
+ * {@link ToStringBuilder}, the output would look like this:
+ *
+ *
+ *
+ * Note: Since field names are mandatory in JSON, this
+ * ToStringStyle will throw an {@link UnsupportedOperationException} if no
+ * field name is passed in while appending. Furthermore This ToStringStyle
+ * will only generate valid JSON if referenced objects also produce JSON
+ * when calling {@code toString()} on them.
+ *
+ * @since 3.4
+ * @see json.org
+ */
+ public static final ToStringStyle JSON_STYLE = new JsonToStringStyle();
+
/**
*
* A registry of objects used by reflectionToString methods
@@ -2326,4 +2349,265 @@ public abstract class ToStringStyle implements Serializable {
}
+ // ----------------------------------------------------------------------------
+
+ /**
+ *
+ * ToStringStyle that outputs with JSON format.
+ *
+ *
+ *
+ * This is an inner class rather than using
+ * StandardToStringStyle to ensure its immutability.
+ *
+ */
+ private static final class JsonToStringStyle extends ToStringStyle {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The summary size text start '>'.
+ */
+ private String FIELD_NAME_PREFIX = "\"";
+
+ /**
+ *
+ * Constructor.
+ *
+ *
+ *
+ * Use the static constant rather than instantiating.
+ *
+ */
+ JsonToStringStyle() {
+ super();
+
+ this.setUseClassName(false);
+ this.setUseIdentityHashCode(false);
+
+ this.setContentStart("{");
+ this.setContentEnd("}");
+
+ this.setArrayStart("[");
+ this.setArrayEnd("]");
+
+ this.setFieldSeparator(",");
+ this.setFieldNameValueSeparator(":");
+
+ this.setNullText("null");
+
+ this.setSummaryObjectStartText("\"<");
+ this.setSummaryObjectEndText(">\"");
+
+ this.setSizeStartText("\"\"");
+ }
+
+ @Override
+ public void append(StringBuffer buffer, String fieldName,
+ Object[] array, Boolean fullDetail) {
+
+ if (fieldName == null) {
+ throw new UnsupportedOperationException(
+ "Field names are mandatory when using JsonToStringStyle");
+ }
+ if (!isFullDetail(fullDetail)){
+ throw new UnsupportedOperationException(
+ "FullDetail must be true when using JsonToStringStyle");
+ }
+
+ super.append(buffer, fieldName, array, fullDetail);
+ }
+
+ @Override
+ public void append(StringBuffer buffer, String fieldName, long[] array,
+ Boolean fullDetail) {
+
+ if (fieldName == null) {
+ throw new UnsupportedOperationException(
+ "Field names are mandatory when using JsonToStringStyle");
+ }
+ if (!isFullDetail(fullDetail)){
+ throw new UnsupportedOperationException(
+ "FullDetail must be true when using JsonToStringStyle");
+ }
+
+ super.append(buffer, fieldName, array, fullDetail);
+ }
+
+ @Override
+ public void append(StringBuffer buffer, String fieldName, int[] array,
+ Boolean fullDetail) {
+
+ if (fieldName == null) {
+ throw new UnsupportedOperationException(
+ "Field names are mandatory when using JsonToStringStyle");
+ }
+ if (!isFullDetail(fullDetail)){
+ throw new UnsupportedOperationException(
+ "FullDetail must be true when using JsonToStringStyle");
+ }
+
+ super.append(buffer, fieldName, array, fullDetail);
+ }
+
+ @Override
+ public void append(StringBuffer buffer, String fieldName,
+ short[] array, Boolean fullDetail) {
+
+ if (fieldName == null) {
+ throw new UnsupportedOperationException(
+ "Field names are mandatory when using JsonToStringStyle");
+ }
+ if (!isFullDetail(fullDetail)){
+ throw new UnsupportedOperationException(
+ "FullDetail must be true when using JsonToStringStyle");
+ }
+
+ super.append(buffer, fieldName, array, fullDetail);
+ }
+
+ @Override
+ public void append(StringBuffer buffer, String fieldName, byte[] array,
+ Boolean fullDetail) {
+
+ if (fieldName == null) {
+ throw new UnsupportedOperationException(
+ "Field names are mandatory when using JsonToStringStyle");
+ }
+ if (!isFullDetail(fullDetail)){
+ throw new UnsupportedOperationException(
+ "FullDetail must be true when using JsonToStringStyle");
+ }
+
+ super.append(buffer, fieldName, array, fullDetail);
+ }
+
+ @Override
+ public void append(StringBuffer buffer, String fieldName, char[] array,
+ Boolean fullDetail) {
+
+ if (fieldName == null) {
+ throw new UnsupportedOperationException(
+ "Field names are mandatory when using JsonToStringStyle");
+ }
+ if (!isFullDetail(fullDetail)){
+ throw new UnsupportedOperationException(
+ "FullDetail must be true when using JsonToStringStyle");
+ }
+
+ super.append(buffer, fieldName, array, fullDetail);
+ }
+
+ @Override
+ public void append(StringBuffer buffer, String fieldName,
+ double[] array, Boolean fullDetail) {
+
+ if (fieldName == null) {
+ throw new UnsupportedOperationException(
+ "Field names are mandatory when using JsonToStringStyle");
+ }
+ if (!isFullDetail(fullDetail)){
+ throw new UnsupportedOperationException(
+ "FullDetail must be true when using JsonToStringStyle");
+ }
+
+ super.append(buffer, fieldName, array, fullDetail);
+ }
+
+ @Override
+ public void append(StringBuffer buffer, String fieldName,
+ float[] array, Boolean fullDetail) {
+
+ if (fieldName == null) {
+ throw new UnsupportedOperationException(
+ "Field names are mandatory when using JsonToStringStyle");
+ }
+ if (!isFullDetail(fullDetail)){
+ throw new UnsupportedOperationException(
+ "FullDetail must be true when using JsonToStringStyle");
+ }
+
+ super.append(buffer, fieldName, array, fullDetail);
+ }
+
+ @Override
+ public void append(StringBuffer buffer, String fieldName,
+ boolean[] array, Boolean fullDetail) {
+
+ if (fieldName == null) {
+ throw new UnsupportedOperationException(
+ "Field names are mandatory when using JsonToStringStyle");
+ }
+ if (!isFullDetail(fullDetail)){
+ throw new UnsupportedOperationException(
+ "FullDetail must be true when using JsonToStringStyle");
+ }
+
+ super.append(buffer, fieldName, array, fullDetail);
+ }
+
+ @Override
+ public void append(StringBuffer buffer, String fieldName, Object value,
+ Boolean fullDetail) {
+
+ if (fieldName == null) {
+ throw new UnsupportedOperationException(
+ "Field names are mandatory when using JsonToStringStyle");
+ }
+ if (!isFullDetail(fullDetail)){
+ throw new UnsupportedOperationException(
+ "FullDetail must be true when using JsonToStringStyle");
+ }
+
+ super.append(buffer, fieldName, value, fullDetail);
+ }
+
+ @Override
+ protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
+
+ if (value == null) {
+
+ appendNullText(buffer, fieldName);
+ return;
+ }
+
+ if (value.getClass() == String.class) {
+
+ appendValueAsString(buffer, (String)value);
+ return;
+ }
+
+ buffer.append(value);
+ }
+
+ private void appendValueAsString(StringBuffer buffer, String value) {
+
+ buffer.append("\"" + value + "\"");
+ }
+
+ @Override
+ protected void appendFieldStart(StringBuffer buffer, String fieldName) {
+
+ if (fieldName == null) {
+ throw new UnsupportedOperationException(
+ "Field names are mandatory when using JsonToStringStyle");
+ }
+
+ super.appendFieldStart(buffer, FIELD_NAME_PREFIX + fieldName
+ + FIELD_NAME_PREFIX);
+ }
+
+ /**
+ *
+ * Ensure Singleton after serialization.
+ *
+ *
+ * @return the singleton
+ */
+ private Object readResolve() {
+ return ToStringStyle.JSON_STYLE;
+ }
+
+ }
}
diff --git a/src/test/java/org/apache/commons/lang3/builder/JsonToStringStyleTest.java b/src/test/java/org/apache/commons/lang3/builder/JsonToStringStyleTest.java
new file mode 100644
index 000000000..0041d9d25
--- /dev/null
+++ b/src/test/java/org/apache/commons/lang3/builder/JsonToStringStyleTest.java
@@ -0,0 +1,414 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.commons.lang3.builder;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.apache.commons.lang3.SystemUtils;
+import org.apache.commons.lang3.builder.ToStringStyleTest.Person;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Unit tests {@link org.apache.commons.lang3.builder.JsonToStringStyleTest}.
+ *
+ * @version $Id$
+ */
+public class JsonToStringStyleTest {
+
+ private final Integer base = Integer.valueOf(5);
+
+ @Before
+ public void setUp() throws Exception {
+ ToStringBuilder.setDefaultStyle(ToStringStyle.JSON_STYLE);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ ToStringBuilder.setDefaultStyle(ToStringStyle.DEFAULT_STYLE);
+ }
+
+ // ----------------------------------------------------------------
+
+ @Test
+ public void testNull() {
+
+ assertEquals(String.valueOf((Object) null),
+ new ToStringBuilder(null).toString());
+ }
+
+ @Test
+ public void testBlank() {
+
+ assertEquals("{}", new ToStringBuilder(base).toString());
+ }
+
+ @Test
+ public void testAppendSuper() {
+
+ assertEquals(
+ "{}",
+ new ToStringBuilder(base).appendSuper(
+ "Integer@8888[" + SystemUtils.LINE_SEPARATOR + "]")
+ .toString());
+ assertEquals(
+ "{}",
+ new ToStringBuilder(base).appendSuper(
+ "Integer@8888[" + SystemUtils.LINE_SEPARATOR + " null"
+ + SystemUtils.LINE_SEPARATOR + "]").toString());
+
+ assertEquals(
+ "{\"a\":\"hello\"}",
+ new ToStringBuilder(base)
+ .appendSuper(
+ "Integer@8888[" + SystemUtils.LINE_SEPARATOR
+ + "]").append("a", "hello").toString());
+
+ assertEquals(
+ "{\"a\":\"hello\"}",
+ new ToStringBuilder(base)
+ .appendSuper(
+ "Integer@8888[" + SystemUtils.LINE_SEPARATOR
+ + " null" + SystemUtils.LINE_SEPARATOR
+ + "]").append("a", "hello").toString());
+
+ assertEquals("{\"a\":\"hello\"}", new ToStringBuilder(base)
+ .appendSuper(null).append("a", "hello").toString());
+ }
+
+ @Test
+ public void testObject() {
+
+ final Integer i3 = Integer.valueOf(3);
+ final Integer i4 = Integer.valueOf(4);
+
+ try {
+
+ assertEquals("{\"null\":null}",
+ new ToStringBuilder(base).append((Object) null).toString());
+
+ fail("Should have generated UnsupportedOperationException");
+
+ } catch (UnsupportedOperationException e) {
+ }
+
+ try {
+
+ assertEquals("{\"null\":3}", new ToStringBuilder(base).append(i3)
+ .toString());
+
+ fail("Should have generated UnsupportedOperationException");
+
+ } catch (UnsupportedOperationException e) {
+ }
+
+ assertEquals("{\"a\":null}",
+ new ToStringBuilder(base).append("a", (Object) null).toString());
+
+ assertEquals("{\"a\":3}", new ToStringBuilder(base).append("a", i3)
+ .toString());
+
+ assertEquals("{\"a\":3,\"b\":4}",
+ new ToStringBuilder(base).append("a", i3).append("b", i4)
+ .toString());
+
+ try {
+ assertEquals("{\"a\":\"\"}",
+ new ToStringBuilder(base).append("a", i3, false).toString());
+
+ fail("Should have generated UnsupportedOperationException");
+
+ } catch (UnsupportedOperationException e) {
+ }
+
+ try {
+
+ assertEquals(
+ "{\"a\":\"\"}",
+ new ToStringBuilder(base).append("a", new ArrayList