Skip to content

Commit

Permalink
Support strict parsing of booleans. #182.
Browse files Browse the repository at this point in the history
  • Loading branch information
pdvrieze committed Oct 4, 2023
1 parent 0539237 commit e44f8ba
Show file tree
Hide file tree
Showing 9 changed files with 333 additions and 3 deletions.
5 changes: 5 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
# 0.86.3-SNAPSHOT
Features:
- Support strict boolean parsing in policy
(using xml schema rules allowing: 1, true, 0, false)
- Add an alias XmlBoolean that parses according to xml rules independent of
the policy.
Fixes:
- Fix handling of empty textual value content.

Expand Down
9 changes: 9 additions & 0 deletions core/api/android/core.api
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,15 @@ public final class nl/adaptivity/xmlutil/util/XMLFragmentStreamReaderJava$Defaul
public static fun require (Lnl/adaptivity/xmlutil/util/XMLFragmentStreamReaderJava;Lnl/adaptivity/xmlutil/EventType;Ljavax/xml/namespace/QName;)V
}

public final class nl/adaptivity/xmlutil/util/XmlBooleanSerializer : kotlinx/serialization/KSerializer {
public static final field INSTANCE Lnl/adaptivity/xmlutil/util/XmlBooleanSerializer;
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Boolean;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Z)V
}

public class nl/adaptivity/xmlutil/util/XmlDelegatingReader : nl/adaptivity/xmlutil/XmlDelegatingReader {
protected fun <init> (Lnl/adaptivity/xmlutil/XmlReader;)V
}
Expand Down
9 changes: 9 additions & 0 deletions core/api/jvm/core.api
Original file line number Diff line number Diff line change
Expand Up @@ -1188,6 +1188,15 @@ public final class nl/adaptivity/xmlutil/util/XMLFragmentStreamReaderJava$Defaul
public static fun require (Lnl/adaptivity/xmlutil/util/XMLFragmentStreamReaderJava;Lnl/adaptivity/xmlutil/EventType;Ljavax/xml/namespace/QName;)V
}

public final class nl/adaptivity/xmlutil/util/XmlBooleanSerializer : kotlinx/serialization/KSerializer {
public static final field INSTANCE Lnl/adaptivity/xmlutil/util/XmlBooleanSerializer;
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Boolean;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Z)V
}

public class nl/adaptivity/xmlutil/util/XmlDelegatingReader : nl/adaptivity/xmlutil/XmlDelegatingReader {
protected fun <init> (Lnl/adaptivity/xmlutil/XmlReader;)V
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2023.
*
* This file is part of xmlutil.
*
* This file is licenced to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You should have received a copy of the license with the source distribution.
* Alternatively, 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 nl.adaptivity.xmlutil.util

import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder

public typealias XmlBoolean = @Serializable(XmlBooleanSerializer::class) Boolean

public object XmlBooleanSerializer : KSerializer<Boolean> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("xmlBoolean", PrimitiveKind.STRING)

override fun serialize(encoder: Encoder, value: Boolean): Unit = when (value) {
true -> encoder.encodeString("true")
else -> encoder.encodeString("false")
}

override fun deserialize(decoder: Decoder): Boolean = when (val s = decoder.decodeString()) {
"0", "false" -> false
"1", "true" -> true
else -> throw NumberFormatException("Invalid boolean value: $s")
}
}
5 changes: 5 additions & 0 deletions serialization/api/android/serialization.api
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public class nl/adaptivity/xmlutil/serialization/DefaultXmlSerializationPolicy :
public fun invalidOutputKind (Ljava/lang/String;)V
public fun isListEluded (Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;)Z
public fun isMapValueCollapsed (Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;Lnl/adaptivity/xmlutil/serialization/structure/XmlDescriptor;)Z
public fun isStrictBoolean ()Z
public fun isStrictNames ()Z
public fun isTransparentPolymorphic (Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;)Z
public fun mapEntryName (Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;Z)Ljavax/xml/namespace/QName;
Expand Down Expand Up @@ -89,10 +90,12 @@ public class nl/adaptivity/xmlutil/serialization/DefaultXmlSerializationPolicy$B
public final fun ignoreNamespaces ()V
public final fun ignoreUnknownChildren ()V
public final fun isStrictAttributeNames ()Z
public final fun isStrictBoolean ()Z
public final fun setAutoPolymorphic (Z)V
public final fun setEncodeDefault (Lnl/adaptivity/xmlutil/serialization/XmlSerializationPolicy$XmlEncodeDefault;)V
public final fun setPedantic (Z)V
public final fun setStrictAttributeNames (Z)V
public final fun setStrictBoolean (Z)V
public final fun setThrowOnRepeatedElement (Z)V
public final fun setTypeDiscriminatorName (Ljavax/xml/namespace/QName;)V
public final fun setUnknownChildHandler (Lnl/adaptivity/xmlutil/serialization/UnknownChildHandler;)V
Expand Down Expand Up @@ -552,6 +555,7 @@ public abstract interface class nl/adaptivity/xmlutil/serialization/XmlSerializa
public abstract fun invalidOutputKind (Ljava/lang/String;)V
public abstract fun isListEluded (Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;)Z
public abstract fun isMapValueCollapsed (Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;Lnl/adaptivity/xmlutil/serialization/structure/XmlDescriptor;)Z
public abstract fun isStrictBoolean ()Z
public abstract fun isStrictNames ()Z
public abstract fun isTransparentPolymorphic (Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;)Z
public abstract fun mapEntryName (Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;Z)Ljavax/xml/namespace/QName;
Expand Down Expand Up @@ -615,6 +619,7 @@ public final class nl/adaptivity/xmlutil/serialization/XmlSerializationPolicy$De
public static fun initialChildReorderMap (Lnl/adaptivity/xmlutil/serialization/XmlSerializationPolicy;Lkotlinx/serialization/descriptors/SerialDescriptor;)Ljava/util/Collection;
public static fun invalidOutputKind (Lnl/adaptivity/xmlutil/serialization/XmlSerializationPolicy;Ljava/lang/String;)V
public static fun isMapValueCollapsed (Lnl/adaptivity/xmlutil/serialization/XmlSerializationPolicy;Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;Lnl/adaptivity/xmlutil/serialization/structure/XmlDescriptor;)Z
public static fun isStrictBoolean (Lnl/adaptivity/xmlutil/serialization/XmlSerializationPolicy;)Z
public static fun isStrictNames (Lnl/adaptivity/xmlutil/serialization/XmlSerializationPolicy;)Z
public static fun mapEntryName (Lnl/adaptivity/xmlutil/serialization/XmlSerializationPolicy;Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;Z)Ljavax/xml/namespace/QName;
public static fun mapKeyName (Lnl/adaptivity/xmlutil/serialization/XmlSerializationPolicy;Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;)Lnl/adaptivity/xmlutil/serialization/XmlSerializationPolicy$DeclaredNameInfo;
Expand Down
5 changes: 5 additions & 0 deletions serialization/api/jvm/serialization.api
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public class nl/adaptivity/xmlutil/serialization/DefaultXmlSerializationPolicy :
public fun invalidOutputKind (Ljava/lang/String;)V
public fun isListEluded (Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;)Z
public fun isMapValueCollapsed (Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;Lnl/adaptivity/xmlutil/serialization/structure/XmlDescriptor;)Z
public fun isStrictBoolean ()Z
public fun isStrictNames ()Z
public fun isTransparentPolymorphic (Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;)Z
public fun mapEntryName (Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;Z)Ljavax/xml/namespace/QName;
Expand Down Expand Up @@ -89,10 +90,12 @@ public class nl/adaptivity/xmlutil/serialization/DefaultXmlSerializationPolicy$B
public final fun ignoreNamespaces ()V
public final fun ignoreUnknownChildren ()V
public final fun isStrictAttributeNames ()Z
public final fun isStrictBoolean ()Z
public final fun setAutoPolymorphic (Z)V
public final fun setEncodeDefault (Lnl/adaptivity/xmlutil/serialization/XmlSerializationPolicy$XmlEncodeDefault;)V
public final fun setPedantic (Z)V
public final fun setStrictAttributeNames (Z)V
public final fun setStrictBoolean (Z)V
public final fun setThrowOnRepeatedElement (Z)V
public final fun setTypeDiscriminatorName (Ljavax/xml/namespace/QName;)V
public final fun setUnknownChildHandler (Lnl/adaptivity/xmlutil/serialization/UnknownChildHandler;)V
Expand Down Expand Up @@ -552,6 +555,7 @@ public abstract interface class nl/adaptivity/xmlutil/serialization/XmlSerializa
public abstract fun invalidOutputKind (Ljava/lang/String;)V
public abstract fun isListEluded (Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;)Z
public abstract fun isMapValueCollapsed (Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;Lnl/adaptivity/xmlutil/serialization/structure/XmlDescriptor;)Z
public abstract fun isStrictBoolean ()Z
public abstract fun isStrictNames ()Z
public abstract fun isTransparentPolymorphic (Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;)Z
public abstract fun mapEntryName (Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;Z)Ljavax/xml/namespace/QName;
Expand Down Expand Up @@ -615,6 +619,7 @@ public final class nl/adaptivity/xmlutil/serialization/XmlSerializationPolicy$De
public static fun initialChildReorderMap (Lnl/adaptivity/xmlutil/serialization/XmlSerializationPolicy;Lkotlinx/serialization/descriptors/SerialDescriptor;)Ljava/util/Collection;
public static fun invalidOutputKind (Lnl/adaptivity/xmlutil/serialization/XmlSerializationPolicy;Ljava/lang/String;)V
public static fun isMapValueCollapsed (Lnl/adaptivity/xmlutil/serialization/XmlSerializationPolicy;Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;Lnl/adaptivity/xmlutil/serialization/structure/XmlDescriptor;)Z
public static fun isStrictBoolean (Lnl/adaptivity/xmlutil/serialization/XmlSerializationPolicy;)Z
public static fun isStrictNames (Lnl/adaptivity/xmlutil/serialization/XmlSerializationPolicy;)Z
public static fun mapEntryName (Lnl/adaptivity/xmlutil/serialization/XmlSerializationPolicy;Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;Z)Ljavax/xml/namespace/QName;
public static fun mapKeyName (Lnl/adaptivity/xmlutil/serialization/XmlSerializationPolicy;Lnl/adaptivity/xmlutil/serialization/structure/SafeParentInfo;)Lnl/adaptivity/xmlutil/serialization/XmlSerializationPolicy$DeclaredNameInfo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import nl.adaptivity.xmlutil.serialization.impl.consumeChunksFromString
import nl.adaptivity.xmlutil.serialization.impl.readSimpleElementChunked
import nl.adaptivity.xmlutil.serialization.structure.*
import nl.adaptivity.xmlutil.util.CompactFragment
import nl.adaptivity.xmlutil.util.XmlBooleanSerializer
import kotlin.collections.set

@OptIn(ExperimentalSerializationApi::class)
Expand Down Expand Up @@ -87,7 +88,10 @@ internal open class XmlDecoderBase internal constructor(
return null
}

override fun decodeBoolean(): Boolean = decodeStringImpl().toBoolean()
override fun decodeBoolean(): Boolean = when {
config.policy.isStrictBoolean -> XmlBooleanSerializer.deserialize(this)
else -> decodeStringImpl().toBoolean()
}

override fun decodeByte(): Byte = when {
xmlDescriptor.isUnsigned -> decodeStringImpl().toUByte().toByte()
Expand Down Expand Up @@ -1115,7 +1119,11 @@ internal open class XmlDecoderBase internal constructor(
}

override fun decodeBooleanElement(descriptor: SerialDescriptor, index: Int): Boolean {
return decodeStringElement(descriptor, index).toBoolean()
val stringValue = decodeStringElement(descriptor, index)
return when {
config.policy.isStrictBoolean -> XmlBooleanSerializer.deserialize(StringDecoder(xmlDescriptor.getElementDescriptor(index), stringValue))
else -> stringValue.toBoolean()
}
}

override fun decodeByteElement(descriptor: SerialDescriptor, index: Int): Byte {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public interface XmlSerializationPolicy {
public val defaultObjectOutputKind: OutputKind get() = OutputKind.Element

public val isStrictNames: Boolean get() = false
public val isStrictBoolean: Boolean get() = false

@ExperimentalXmlUtilApi
public val verifyElementOrder: Boolean get() = false
Expand Down Expand Up @@ -305,6 +306,7 @@ private constructor(
public val throwOnRepeatedElement: Boolean = false,
public override val verifyElementOrder: Boolean = false,
public override val isStrictNames: Boolean,
public override val isStrictBoolean: Boolean = false,
) : XmlSerializationPolicy {

@Deprecated("Use builder")
Expand Down Expand Up @@ -380,7 +382,8 @@ private constructor(
typeDiscriminatorName = (original as? DefaultXmlSerializationPolicy)?.typeDiscriminatorName,
throwOnRepeatedElement = (original as? DefaultXmlSerializationPolicy)?.throwOnRepeatedElement ?: false,
verifyElementOrder = original?.verifyElementOrder ?: false,
isStrictNames = original?.isStrictNames ?: false
isStrictNames = original?.isStrictNames ?: false,
isStrictBoolean = original?.isStrictBoolean ?: false,
)

@OptIn(ExperimentalXmlUtilApi::class)
Expand All @@ -393,6 +396,7 @@ private constructor(
throwOnRepeatedElement = builder.throwOnRepeatedElement,
verifyElementOrder = builder.verifyElementOrder,
isStrictNames = builder.isStrictAttributeNames,
isStrictBoolean = builder.isStrictBoolean,
)

override fun polymorphicDiscriminatorName(serializerParent: SafeParentInfo, tagParent: SafeParentInfo): QName? {
Expand Down Expand Up @@ -798,6 +802,7 @@ private constructor(
public var throwOnRepeatedElement: Boolean = false,
public var verifyElementOrder: Boolean = false,
public var isStrictAttributeNames: Boolean = false,
public var isStrictBoolean: Boolean = false,
) {
internal constructor(policy: DefaultXmlSerializationPolicy) : this(
pedantic = policy.pedantic,
Expand Down
Loading

0 comments on commit e44f8ba

Please sign in to comment.