diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/StringUtils.java b/smack-core/src/main/java/org/jivesoftware/smack/util/StringUtils.java index 77bc402c3..5ebe4c116 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/StringUtils.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/StringUtils.java @@ -1,6 +1,6 @@ /** * - * Copyright 2003-2007 Jive Software, 2016-2020 Florian Schmaus. + * Copyright 2003-2007 Jive Software, 2016-2021 Florian Schmaus. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package org.jivesoftware.smack.util; import java.io.IOException; import java.nio.CharBuffer; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; @@ -605,4 +606,13 @@ public class StringUtils { String[] lines = input.split(PORTABLE_NEWLINE_REGEX); return Arrays.asList(lines); } + + public static List toStrings(Collection charSequences) { + List res = new ArrayList<>(charSequences.size()); + for (CharSequence cs : charSequences) { + String string = cs.toString(); + res.add(string); + } + return res; + } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/caps/EntityCapsManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/caps/EntityCapsManager.java index 034d0f9dd..7f481ab21 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/caps/EntityCapsManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/caps/EntityCapsManager.java @@ -700,7 +700,7 @@ public final class EntityCapsManager extends Manager { for (FormField f : fs) { sb.append(f.getFieldName()); sb.append('<'); - formFieldValuesToCaps(f.getRawValues(), sb); + formFieldValuesToCaps(f.getRawValueCharSequences(), sb); } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/FormNode.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/FormNode.java index 3a6945f0f..ef8f3373c 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/FormNode.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/FormNode.java @@ -38,11 +38,7 @@ public class FormNode extends NodeExtension { * @param submitForm The form */ public FormNode(FormNodeType formType, DataForm submitForm) { - super(formType.getNodeElement()); - - if (submitForm == null) - throw new IllegalArgumentException("Submit form cannot be null"); - configForm = submitForm; + this(formType, null, submitForm); } /** @@ -55,9 +51,6 @@ public class FormNode extends NodeExtension { */ public FormNode(FormNodeType formType, String nodeId, DataForm submitForm) { super(formType.getNodeElement(), nodeId); - - if (submitForm == null) - throw new IllegalArgumentException("Submit form cannot be null"); configForm = submitForm; } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/provider/FormNodeProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/provider/FormNodeProvider.java index e7d8b0946..5c5d71dc7 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/provider/FormNodeProvider.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/provider/FormNodeProvider.java @@ -35,6 +35,11 @@ import org.jivesoftware.smackx.xdata.packet.DataForm; public class FormNodeProvider extends EmbeddedExtensionProvider { @Override protected FormNode createReturnExtension(String currentElement, String currentNamespace, Map attributeMap, List content) { - return new FormNode(FormNodeType.valueOfFromElementName(currentElement, currentNamespace), attributeMap.get("node"), (DataForm) content.iterator().next()); + DataForm dataForm = null; + if (!content.isEmpty()) { + dataForm = (DataForm) content.get(0); + } + + return new FormNode(FormNodeType.valueOfFromElementName(currentElement, currentNamespace), attributeMap.get("node"), dataForm); } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/AbstractMultiFormField.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/AbstractMultiFormField.java index 4b1c092b3..16ccc3c7f 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/AbstractMultiFormField.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/AbstractMultiFormField.java @@ -27,35 +27,26 @@ import org.jxmpp.util.XmppDateTime; public class AbstractMultiFormField extends FormField { - private final List values; - - private final List rawValues; + private final List values; protected AbstractMultiFormField(Builder builder) { super(builder); values = CollectionUtil.cloneAndSeal(builder.values); - rawValues = CollectionUtil.cloneAndSeal(builder.rawValues); } @Override - public final List getValues() { + public final List getRawValues() { return values; } - @Override - public final List getRawValues() { - return rawValues; - } - public abstract static class Builder> extends FormField.Builder { - private List values; - private List rawValues; + private List values; protected Builder(AbstractMultiFormField formField) { super(formField); - values = CollectionUtil.newListWith(formField.getValues()); + values = CollectionUtil.newListWith(formField.getRawValues()); } protected Builder(String fieldName, FormField.Type type) { @@ -65,7 +56,6 @@ public class AbstractMultiFormField extends FormField { private void ensureValuesAreInitialized() { if (values == null) { values = new ArrayList<>(); - rawValues = new ArrayList<>(); } } @@ -77,11 +67,13 @@ public class AbstractMultiFormField extends FormField { public abstract B addValue(CharSequence value); public B addValueVerbatim(CharSequence value) { + return addValueVerbatim(new Value(value)); + } + + public B addValueVerbatim(Value value) { ensureValuesAreInitialized(); - String valueString = value.toString(); - values.add(valueString); - rawValues.add(valueString); + values.add(value); return getThis(); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/AbstractSingleStringValueFormField.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/AbstractSingleStringValueFormField.java index 4530d3968..9e57a294e 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/AbstractSingleStringValueFormField.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/AbstractSingleStringValueFormField.java @@ -74,8 +74,15 @@ public class AbstractSingleStringValueFormField extends SingleValueFormField { return setValue(value); } + public B setValue(Value value) { + this.value = value.getValue().toString(); + this.rawValue = value; + return getThis(); + } + public B setValue(CharSequence value) { - this.rawValue = this.value = value.toString(); + this.value = value.toString(); + rawValue = new Value(this.value); return getThis(); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/BooleanFormField.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/BooleanFormField.java index e87278ae9..85e351649 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/BooleanFormField.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/BooleanFormField.java @@ -71,17 +71,21 @@ public class BooleanFormField extends SingleValueFormField { @Deprecated // TODO: Remove in Smack 4.6. public Builder addValue(CharSequence value) { - return setValue(value); + return setValue(new Value(value)); } public Builder setValue(CharSequence value) { - rawValue = value.toString(); - boolean valueBoolean = ParserUtils.parseXmlBoolean(rawValue); - return setValue(valueBoolean); + return setValue(new Value(value)); + } + + public Builder setValue(Value value) { + this.value = ParserUtils.parseXmlBoolean(value.getValue().toString()); + rawValue = value; + return getThis(); } public Builder setValue(boolean value) { - rawValue = Boolean.toString(value); + rawValue = new Value(Boolean.toString(value)); this.value = value; return this; } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/FormField.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/FormField.java index 8f4e9aafd..acf4f276d 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/FormField.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/FormField.java @@ -269,9 +269,25 @@ public abstract class FormField implements XmlElement { * * @return a List of the default values or answered values of the question. */ - public abstract List getValues(); + public List getValues() { + return getRawValueCharSequences(); + } - public abstract List getRawValues(); + public abstract List getRawValues(); + + private transient List rawValueCharSequences; + + public final List getRawValueCharSequences() { + if (rawValueCharSequences == null) { + List rawValues = getRawValues(); + rawValueCharSequences = new ArrayList<>(rawValues.size()); + for (Value value : rawValues) { + rawValueCharSequences.add(value.value); + } + } + + return rawValueCharSequences; + } public boolean hasValueSet() { List values = getValues(); @@ -385,12 +401,15 @@ public abstract class FormField implements XmlElement { protected transient List extraXmlChildElements; + /** + * Populate @{link {@link #extraXmlChildElements}}. Note that this method may be overridden by subclasses. + */ protected void populateExtraXmlChildElements() { - List values = getValues(); + List values = getRawValues(); + // Note that we need to create a new ArrayList here, since subclasses may add to it by overriding + // populateExtraXmlChildElements. extraXmlChildElements = new ArrayList<>(values.size()); - for (CharSequence value : values) { - extraXmlChildElements.add(new Value(value)); - } + extraXmlChildElements.addAll(values); } @Override @@ -414,7 +433,8 @@ public abstract class FormField implements XmlElement { populateExtraXmlChildElements(); } - if (formFieldChildElements.isEmpty() && extraXmlChildElements == null) { + if (formFieldChildElements.isEmpty() + && (extraXmlChildElements == null || extraXmlChildElements.isEmpty())) { buf.closeEmptyElement(); } else { buf.rightAngleBracket(); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/JidMultiFormField.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/JidMultiFormField.java index a5c869c18..39d8357af 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/JidMultiFormField.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/JidMultiFormField.java @@ -23,13 +23,14 @@ import java.util.List; import org.jivesoftware.smack.util.CollectionUtil; import org.jxmpp.jid.Jid; -import org.jxmpp.jid.util.JidUtil; +import org.jxmpp.jid.impl.JidCreate; +import org.jxmpp.stringprep.XmppStringprepException; public final class JidMultiFormField extends FormField { private final List values; - private final List rawValues; + private final List rawValues; JidMultiFormField(Builder builder) { super(builder); @@ -43,7 +44,7 @@ public final class JidMultiFormField extends FormField { } @Override - public List getRawValues() { + public List getRawValues() { return rawValues; } @@ -54,7 +55,7 @@ public final class JidMultiFormField extends FormField { public static final class Builder extends FormField.Builder { private List values; - private List rawValues; + private List rawValues; private Builder(JidMultiFormField jidMultiFormField) { super(jidMultiFormField); @@ -79,27 +80,29 @@ public final class JidMultiFormField extends FormField { } public Builder addValue(Jid jid) { - return addValue(jid, null); - } - - public Builder addValue(Jid jid, String rawValue) { - if (rawValue == null) { - rawValue = jid.toString(); - } + Value value = new Value(jid); ensureValuesAreInitialized(); - values.add(jid); - rawValues.add(rawValue); + rawValues.add(value); + + return getThis(); + } + + public Builder addValue(Value value) throws XmppStringprepException { + Jid jid = JidCreate.from(value.getValue()); + + ensureValuesAreInitialized(); + values.add(jid); + rawValues.add(value); return this; } public Builder addValues(Collection jids) { - ensureValuesAreInitialized(); - - values.addAll(jids); - rawValues.addAll(JidUtil.toStringList(jids)); + for (Jid jid : jids) { + addValue(jid); + } return this; } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/JidSingleFormField.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/JidSingleFormField.java index 7948971a3..ec5ec4c70 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/JidSingleFormField.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/JidSingleFormField.java @@ -17,6 +17,8 @@ package org.jivesoftware.smackx.xdata; import org.jxmpp.jid.Jid; +import org.jxmpp.jid.impl.JidCreate; +import org.jxmpp.stringprep.XmppStringprepException; public class JidSingleFormField extends SingleValueFormField { @@ -60,11 +62,13 @@ public class JidSingleFormField extends SingleValueFormField { public Builder setValue(Jid value, String rawValue) { this.value = value; - if (rawValue != null) { - this.rawValue = rawValue; - } else { - this.rawValue = value.toString(); - } + this.rawValue = new Value(value); + return getThis(); + } + + public Builder setValue(Value value) throws XmppStringprepException { + this.value = JidCreate.from(value.getValue()); + this.rawValue = value; return this; } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/SingleValueFormField.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/SingleValueFormField.java index 796abd654..d4b389a96 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/SingleValueFormField.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/SingleValueFormField.java @@ -23,7 +23,7 @@ import org.jivesoftware.smack.util.CollectionUtil; public abstract class SingleValueFormField extends FormField { - private final String rawValue; + private final Value rawValue; protected SingleValueFormField(Builder builder) { super(builder); @@ -38,24 +38,23 @@ public abstract class SingleValueFormField extends FormField { public abstract CharSequence getValue(); - public final String getRawValue() { + public final Value getRawValue() { return rawValue; } @Override - public final List getRawValues() { - String rawValue = getRawValue(); + public final List getRawValues() { + Value rawValue = getRawValue(); return CollectionUtil.emptyOrSingletonListFrom(rawValue); } @Override protected void populateExtraXmlChildElements() { - CharSequence value = getValue(); - if (value == null) { + if (rawValue == null) { return; } - extraXmlChildElements = Collections.singletonList(new Value(value)); + extraXmlChildElements = Collections.singletonList(rawValue); } public abstract static class Builder> @@ -65,11 +64,12 @@ public abstract class SingleValueFormField extends FormField { super(fieldName, type); } - protected Builder(FormField formField) { + protected Builder(SingleValueFormField formField) { super(formField); + rawValue = formField.getRawValue(); } - protected String rawValue; + protected Value rawValue; @Override protected void resetInternal() { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/form/FormReader.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/form/FormReader.java index 493abd25a..043e9a1fe 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/form/FormReader.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/form/FormReader.java @@ -1,6 +1,6 @@ /** * - * Copyright 2020 Florian Schmaus + * Copyright 2020-2021 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,8 @@ import java.util.Collections; import java.util.Date; import java.util.List; +import org.jivesoftware.smack.util.StringUtils; + import org.jivesoftware.smackx.xdata.AbstractMultiFormField; import org.jivesoftware.smackx.xdata.AbstractSingleStringValueFormField; import org.jivesoftware.smackx.xdata.BooleanFormField; @@ -54,7 +56,8 @@ public interface FormReader { return Collections.emptyList(); } AbstractMultiFormField multiFormField = formField.ifPossibleAs(AbstractMultiFormField.class); - return multiFormField.getValues(); + List charSequences = multiFormField.getValues(); + return StringUtils.toStrings(charSequences); } default Boolean readBoolean(String fieldName) { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/provider/DataFormProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/provider/DataFormProvider.java index f6362660c..0be42d61f 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/provider/DataFormProvider.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/provider/DataFormProvider.java @@ -49,9 +49,6 @@ import org.jivesoftware.smackx.xdata.packet.DataForm; import org.jivesoftware.smackx.xdatalayout.packet.DataLayout; import org.jivesoftware.smackx.xdatalayout.provider.DataLayoutProvider; -import org.jxmpp.jid.Jid; -import org.jxmpp.jid.impl.JidCreate; - /** * The DataFormProvider parses DataForm packets. * @@ -237,9 +234,7 @@ public class DataFormProvider extends ExtensionElementProvider { case jid_multi: JidMultiFormField.Builder jidMultiBuilder = FormField.jidMultiBuilder(fieldName); for (FormField.Value value : values) { - String rawValue = value.getValue().toString(); - Jid jid = JidCreate.from(rawValue); - jidMultiBuilder.addValue(jid, rawValue); + jidMultiBuilder.addValue(value); } builder = jidMultiBuilder; break; @@ -247,9 +242,8 @@ public class DataFormProvider extends ExtensionElementProvider { ensureAtMostSingleValue(type, values); JidSingleFormField.Builder jidSingleBuilder = FormField.jidSingleBuilder(fieldName); if (!values.isEmpty()) { - String rawValue = values.get(0).getValue().toString(); - Jid jid = JidCreate.from(rawValue); - jidSingleBuilder.setValue(jid, rawValue); + FormField.Value value = values.get(0); + jidSingleBuilder.setValue(value); } builder = jidSingleBuilder; break; @@ -303,7 +297,7 @@ public class DataFormProvider extends ExtensionElementProvider { BooleanFormField.Builder builder = FormField.booleanBuilder(fieldName); ensureAtMostSingleValue(builder.getType(), values); if (values.size() == 1) { - String value = values.get(0).getValue().toString(); + FormField.Value value = values.get(0); builder.setValue(value); } return builder;