In ASP NET 6+ I need to make [FromQuery] replace underscores _ and minuses - before matching names.
So I want to plumb ASP to allow [FromQuery] bool testValue to be equivalent to all at once:
[FromQuery(Name="testValue")] bool testValue
[FromQuery(Name="test-value")] bool testValue
[FromQuery(Name="test_value")] bool testValue
Is there a place in the pipeline I can get in before names are compared (to remove _ and - myself)?
My current solution is just to replace the Request.Query with my own doctored QueryCollection that duplicates variables with fixed names in a middleware.
But I'm looking for any answer that's more... unhacky?!
public class RequeryMiddleware : IMiddleware
{
private static readonly char[] separators = new[] { '_', '-', '.', '|' };
private static bool Requery(ref string name)
{
bool changed = false;
if (name.IndexOfAny(separators) >= 0)
{
name = string.Concat(name.Split(separators, StringSplitOptions.None));
changed = true;
}
return changed;
}
public Task InvokeAsync(HttpContext context, RequestDelegate next)
{
Dictionary<string, StringValues> mods = new(
StringComparer.OrdinalIgnoreCase
);
foreach (var item in context.Request.Query)
{
string key = item.Key;
if (Requery(ref key))
{
mods.Add(key, item.Value);
}
}
if (mods.Count > 0)
{
Dictionary<string, StringValues> query = new(
context.Request.Query.Count + mods.Count
, StringComparer.OrdinalIgnoreCase
);
foreach (var item in context.Request.Query)
{
query.Add(item.Key, item.Value);
}
foreach (var mod in mods)
{
// if we get here it's bad...
query.TryAdd(mod.Key, mod.Value);
}
// replace the Query collection
context.Request.Query = new QueryCollection(query);
// change the QueryString too
QueryBuilder qb = new(context.Request.Query);
context.Request.QueryString = qb.ToQueryString();
}
return next(context);
}
}
My method toString() is supposed to return a string representation of the stack. The string representation consists of the stacks's elements in the order they are stored, enclosed in square brackets. My problem is that I am now returning [element0, element1, element2, element3, element4] so I wonder if there is there a simple way to return the string in reverse order i.e. to return [element4, element3, element2, element1, element0] instead?
public class Stack<E> implements IStack<E> {
public String toString() {
String str = "[";
if (head != null) {
str += head.getmElement();
Node<E> tempNode = head.getmNextNode();
while (tempNode != null) {
str += ", " + tempNode.getmElement();
tempNode = tempNode.getmNextNode();
}
}
str += "]";
return str; }
Node class:
public class Node<E> {
private E mElement;
private Node<E> mNextNode;
Node(E data) {
this.setmElement(data);
}
public E getmElement() {
return this.mElement;
}
public void setmElement(E element) {
this.mElement = element;
}
public Node<E> getmNextNode()
{
return this.mNextNode;
}
public void setmNextNode(Node<E> node)
{
this.mNextNode = node;
}}
You could use a StringBuilder and insert every element at the beginning instead of appending it:
public String toString() {
StringBuilder sb = new StringBuilder("[");
if (head != null) {
sb.append(head.getmElement());
Node<E> tempNode = head.getmNextNode();
while (tempNode != null) {
sb.insert(1, ", ").inser(1, tempNode.getmElement());
tempNode = tempNode.getmNextNode();
}
}
sb.append("]");
return sb.toString();
}
Your list is only forward linked, so you could use a temporary ArrayList and add each element at the index 0.
Facing compilation error when using #Factory with #DataProvider.
Trying to map hashmap to my dataprovider, and want to run all my testcase with first testdata row then next, so trying to use #Factory
HashMap < String, String testdata = new HashMap < String, String();
#Test
private void test_01() {
System.out.println(testdata.get("-some-hashmap-key-"));
}
#DataProvider
public static Object[][] getDataSet() {
int i = 0;
Object[][] dataSet = new Object[2][1];
HashMap < String, String > rowValuesMap = new HashMap();
for (-some logic - ) {
for (-some logic - ) {
dataSet[i][0] = rowValuesMap;
}
i++;
}
return dataSet;
}
#Factory(dataProvider = "getDataSet")
public MyTestFile(HashMap < String, String testdata) {
this.testdata = sheetdata;
}
HashMap declaration is wrong in all place. Try this
HashMap < String, String > testdata = new HashMap < String, String > ();
#Test
private void test_01() {
System.out.println(testdata.get("-some-hashmap-key-"));
}
#DataProvider
public static Object[][] getDataSet() {
int i = 0;
Object[][] dataSet = new Object[2][1];
HashMap < String, String > rowValuesMap = new HashMap < String, String > ();
for (-some logic - ) {
for (-some logic - ) {
dataSet[i][0] = rowValuesMap;
}
i++;
}
return dataSet;
}
#Factory(dataProvider = "getDataSet")
public MyTestFile(HashMap < String, String > testdata) {
this.testdata = sheetdata;
}
From the previous question How to deserialize a JSON array to a singly linked list , I learned how to deserialize a JSON array to a singly linked list.
Now I want to deserialize a JSON object to a binary tree in Java.
The definition of the binary tree node is as the following:
public class BinaryTreeNode<E> {
public E value;
public BinaryTreeNode left;
public BinaryTreeNode right;
public BinaryTreeNode(final E value) {
this.value = value;
}
}
How to deserialize a JSON string such as:
{
"value": 2,
"left": {
"value": 1,
"left": null,
"right": null
},
"right": {
"value": 10,
"left": {
"value": 5,
"left": null,
"right": null
},
"right": null
}
}
to a binary tree?
2
/ \
1 10
/
5
Here is the unit test code:
#Test public void binaryTreeNodeTest() throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
final ArrayList<Integer> intArray = objectMapper.readValue("[1,2,3,4,5]",
new TypeReference<ArrayList<Integer>>() {});
System.out.println(intArray);
/* How to achieve this?
2
/ \
1 10
/
5
{
"value": 2,
"left": {
"value": 1,
"left": null,
"right": null
},
"right": {
"value": 10,
"left": {
"value": 5,
"left": null,
"right": null
},
"right": null
}
}
*/
final String jsonStr = "{\n"
+ " \"value\": 2,\n"
+ " \"left\": {\n"
+ " \"value\": 1,\n"
+ " \"left\": null,\n"
+ " \"right\": null\n"
+ " },\n" + " \"right\": {\n"
+ " \"value\": 10,\n"
+ " \"left\": {\n"
+ " \"value\": 5,\n"
+ " \"left\": null,\n"
+ " \"right\": null\n"
+ " },\n"
+ " \"right\": null\n"
+ " }\n"
+ "}";
System.out.println(jsonStr);
final BinaryTreeNode<Integer> intTree = objectMapper.readValue(jsonStr,
new TypeReference<BinaryTreeNode<Integer>>() {});
System.out.println(intTree);
}
In other word, I want the BinaryTreeNode to be a first-class citizen the same as ArrayList, which can be used in all kinds of combinations, such as HashSet<BinaryTreeNode<Integer>>, BinaryTreeNode<HashMap<String, Integer>>, etc.
The solution is quite simple, since JSON can express tree naturally, Jackson can deal with recursive tree directly. Just annotate a constructor with JsonCreator:
public static class BinaryTreeNode<E>
{
public E value;
public BinaryTreeNode left;
public BinaryTreeNode right;
#JsonCreator
public BinaryTreeNode(#JsonProperty("value") final E value) {
this.value = value;
}
}
Let's write a unite test to try it:
package me.soulmachine.customized_collection;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.assertEquals;
public class BinaryTreeNodeTest {
public static class BinaryTreeNode<E> {
public E value;
public BinaryTreeNode left;
public BinaryTreeNode right;
#JsonCreator
public BinaryTreeNode(#JsonProperty("value") final E value) {
this.value = value;
}
ArrayList<E> preOrder() {
final ArrayList<E> result = new ArrayList<>();
if (this.value == null) {
return result;
}
preOrder(this, result);
return result;
}
private static <E> void preOrder(BinaryTreeNode<E> root, ArrayList<E> result) {
if (root == null)
return;
result.add(root.value);
if (root.left != null)
preOrder(root.left, result);
if (root.right != null)
preOrder(root.right, result);
}
}
#Test public void binaryTreeNodeTest() throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
/*
2
/ \
1 10
/
5
*/
final String jsonStr = "{\n"
+ " \"value\": 2,\n"
+ " \"left\": {\n"
+ " \"value\": 1,\n"
+ " \"left\": null,\n"
+ " \"right\": null\n"
+ " },\n" + " \"right\": {\n"
+ " \"value\": 10,\n"
+ " \"left\": {\n"
+ " \"value\": 5,\n"
+ " \"left\": null,\n"
+ " \"right\": null\n"
+ " },\n"
+ " \"right\": null\n"
+ " }\n"
+ "}";
System.out.println(jsonStr);
final BinaryTreeNode<Integer> intTree = objectMapper.readValue(jsonStr,
new TypeReference<BinaryTreeNode<Integer>>() {});
final List<Integer> listExpected = Arrays.asList(2, 1, 10, 5);
assertEquals(listExpected, intTree.preOrder());
}
}
A compact serialization format
Well, there is a little problem here, the JSON string above is very verbose. Let's use another kind of serialization format, i.e., serialize a binary tree in level order traversal. For example, the binary tree above can be serialized as the following JSON string:
[2,1,10,null,null,5]
Now how to deserialize this JSON string to a binary tree?
The idea is very similar to my previous article, Deserialize a JSON Array to a Singly Linked List. Just make the BinaryTreeNode implement java.util.list, pretend that it's a list, write our own deserialization code so that Jackson can treat a binary tree as a list.
The complete code of BinaryTreeNode is as the following:
package me.soulmachine.customized_collection;
import java.util.*;
public class BinaryTreeNode<E> extends AbstractSequentialList<E>
implements Cloneable, java.io.Serializable {
public E value;
public BinaryTreeNode<E> left;
public BinaryTreeNode<E> right;
/** has a left child, but it's a null node. */
private transient boolean leftIsNull;
/** has a right child, but it's a null node. */
private transient boolean rightIsNull;
/**
* Constructs an empty binary tree.
*/
public BinaryTreeNode() {
value = null;
left = null;
right = null;
}
/**
* Constructs an binary tree with one element.
*/
public BinaryTreeNode(final E value) {
if (value == null) throw new IllegalArgumentException("null value");
this.value = value;
left = null;
right = null;
}
/**
* Constructs a binary tree containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* #param c the collection whose elements are to be placed into this binary tree
* #throws NullPointerException if the specified collection is null
*/
public BinaryTreeNode(Collection<? extends E> c) {
this();
addAll(c);
}
/**
* #inheritDoc
*
* <p>Note: null in the middle counts, so that each father in the binary tree has a
* one-to-one mapping with the JSON array.</p>
*/
public int size() {
if (value == null) return 0;
Queue<BinaryTreeNode<E>> queue = new LinkedList<>();
queue.add(this);
int count = 0;
while (!queue.isEmpty()) {
final BinaryTreeNode<E> node = queue.remove();
++count;
if (node.left != null) {
queue.add(node.left);
} else {
if (node.leftIsNull) ++count;
}
if (node.right != null) {
queue.add(node.right);
} else {
if (node.rightIsNull) ++count;
}
}
return count;
}
/**
* Tells if the argument is the index of a valid position for an
* iterator or an add operation.
*/
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size();
}
/**
* Constructs an IndexOutOfBoundsException detail message.
* Of the many possible refactorings of the error handling code,
* this "outlining" performs best with both server and client VMs.
*/
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+ size();
}
private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private class NodeAndFather {
private BinaryTreeNode<E> node;
private BinaryTreeNode<E> father;
private boolean isRight; // the father is the right child of the father
private NodeAndFather(BinaryTreeNode<E> node, BinaryTreeNode<E> father, boolean isRight) {
this.node = node;
this.father = father;
this.isRight = isRight;
}
}
/**
* Returns the (may be null) Node at the specified element index.
*/
NodeAndFather node(int index) {
checkPositionIndex(index);
if (value == null) return null;
Queue<NodeAndFather> queue = new LinkedList<>();
queue.add(new NodeAndFather(this, null, false));
for (int i = 0; !queue.isEmpty(); ++i) {
final NodeAndFather nodeAndFather = queue.remove();
if ( i == index) {
return nodeAndFather;
}
if (nodeAndFather.node != null) {
queue.add(new NodeAndFather(nodeAndFather.node.left, nodeAndFather.node, false));
queue.add(new NodeAndFather(nodeAndFather.node.right, nodeAndFather.node, true));
}
}
throw new IllegalArgumentException("Illegal index: " + index);
}
/**
* #inheritDoc
*/
public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index);
}
private class ListItr implements ListIterator<E> {
private NodeAndFather next;
private int nextIndex;
private int expectedModCount = modCount;
ListItr(int index) {
assert isPositionIndex(index);
next = node(index);
nextIndex = index;
}
public boolean hasNext() {
final BinaryTreeNode<E> cur = next.node;
return cur != null || (next.father.leftIsNull || next.father.rightIsNull);
}
//O(n)
public E next() {
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();
final E result = next.node != null ? next.node.value : null;
next = node(nextIndex+1);
nextIndex++;
return result;
}
public boolean hasPrevious() {
throw new UnsupportedOperationException();
}
public E previous() {
throw new UnsupportedOperationException();
}
public int nextIndex() {
throw new UnsupportedOperationException();
}
public int previousIndex() {
throw new UnsupportedOperationException();
}
public void remove() {
throw new UnsupportedOperationException();
}
public void set(E e) {
throw new UnsupportedOperationException();
}
public void add(E e) { // always append at the tail
checkForComodification();
if (next == null) { // empty list
BinaryTreeNode.this.value = e;
BinaryTreeNode.this.left = null;
BinaryTreeNode.this.right = null;
} else {
final BinaryTreeNode<E> newNode = e != null ? new BinaryTreeNode<>(e) : null;
if (next.father == null) { // root
BinaryTreeNode<E> cur = next.node;
cur.left = newNode;
assert cur.right == null;
throw new UnsupportedOperationException();
} else {
if (next.isRight) {
if (next.father.right != null) throw new IllegalStateException();
next.father.right = newNode;
if (newNode == null) {
next.father.rightIsNull = true;
}
} else {
if (next.father.left != null) throw new IllegalStateException();
next.father.left = newNode;
if (newNode == null) {
next.father.leftIsNull = true;
}
}
}
}
modCount++;
expectedModCount++;
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
// the following functions are just for unit tests.
ArrayList<E> preOrder() {
final ArrayList<E> result = new ArrayList<>();
if (this.value == null) {
return result;
}
preOrder(this, result);
return result;
}
private static <E> void preOrder(BinaryTreeNode<E> root, ArrayList<E> result) {
if (root == null)
return;
result.add(root.value);
if (root.left != null)
preOrder(root.left, result);
if (root.right != null)
preOrder(root.right, result);
}
ArrayList<E> inOrder() {
final ArrayList<E> result = new ArrayList<>();
if (this.value == null) {
return result;
}
inOrder(this, result);
return result;
}
private static <E> void inOrder(BinaryTreeNode<E> root, ArrayList<E> result) {
if (root == null)
return;
if (root.left != null)
inOrder(root.left, result);
result.add(root.value);
if (root.right != null)
inOrder(root.right, result);
}
ArrayList<E> postOrder() {
final ArrayList<E> result = new ArrayList<>();
if (this.value == null) {
return result;
}
postOrder(this, result);
return result;
}
private static <E> void postOrder(BinaryTreeNode<E> root, ArrayList<E> result) {
if (root == null)
return;
if (root.left != null)
postOrder(root.left, result);
if (root.right != null)
postOrder(root.right, result);
result.add(root.value);
}
ArrayList<E> levelOrder() {
final ArrayList<E> result = new ArrayList<>();
if (this.value == null) {
return result;
}
Queue<BinaryTreeNode<E>> queue = new LinkedList<>();
queue.add(this);
while (!queue.isEmpty()) {
final BinaryTreeNode<E> node = queue.remove();
result.add(node.value);
if (node.left != null)
queue.add(node.left);
if (node.right != null)
queue.add(node.right);
}
return result;
}
}
Then comes with the unit tests:
java
package me.soulmachine.customized_collection;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.assertEquals;
public class BinaryTreeNodeTest
{
#Test public void deserializeTest() throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
final List<Integer> intList = Arrays.asList(2,1,10,null,null,5);
/*
2
/ \
1 10
/
5
*/
// TODO: the time complexity is O(n^2)
final BinaryTreeNode<Integer> intTree = objectMapper.readValue("[2,1,10,null,null,5]",
new TypeReference<BinaryTreeNode<Integer>>() {});
assertEquals(intList, intTree);
assertEquals(Arrays.asList(2, 1, 10, 5), intTree.levelOrder());
assertEquals(Arrays.asList(2, 1, 10, 5), intTree.preOrder());
assertEquals(Arrays.asList(1, 2, 5, 10), intTree.inOrder());
assertEquals(Arrays.asList(1, 5, 10, 2), intTree.postOrder());
}
}
This article is inspired by Tatu Saloranta from this post, special thanks to him!
Here is my original blog, Deserialize a JSON String to a Binary Tree
I would like to know the best way to compare 2 complex objects to know if they are equal by value, ie, their properties are the same? I tried the serialize method and not sure why they are not equal by value
Dim stream As New MemoryStream()
Dim bstream As New MemoryStream()
Dim clientOne As Jewellery.ClientInfo = New Jewellery.ClientInfo(New Jewellery.Company("a", "", "", "b", "", "e"), New Jewellery.Customer("a", "b", "c", "d", "", "", "", "f"))
Dim clientTwo As Jewellery.ClientInfo = New Jewellery.ClientInfo(New Jewellery.Company("a", "", "", "b", "", "e"), New Jewellery.Customer("a", "b", "c", "d", "", "", "", "f"))
formatter.Serialize(stream, clientOne)
formatter.Serialize(bstream, clientTwo)
Dim streamOneBytes As Byte() = stream.ToArray()
Dim streamTwoBytes As Byte() = bstream.ToArray()
Dim streamToCompareBytes As Byte() = streamToCompare.ToArray()
Dim i As Int16 = 0
Dim flag As Boolean
If streamOneBytes.Length <> streamTwoBytes.Length Then
MsgBox("False")
flag = False
Else
While i < streamOneBytes.Count
If streamOneBytes(i) <> streamTwoBytes(i) Then
flag = "False"
Else : flag = "True"
End If
i = i + 1
End While
End If
As you see in the above code, when I initialize 2 objects of the same type and compare, it works correctly. But when I add one object to say a List and then retrieve and compare to an object of similar type, it fails saying the binary width are different for both. Any advice? Thanks
public class IntegerPropertyEqualityCompare : IEqualityComparer<Main>
{
#region IEqualityComparer<Main> Members
public bool Equals( Main x, Main y )
{
return x.IntegerProperty == y.IntegerProperty;
}
public int GetHashCode( Main obj )
{
return obj.IntegerProperty.GetHashCode() ^ obj.StringProperty.GetHashCode();
}
#endregion
}
public class StringPropertyEqualityCompare : IEqualityComparer<Main>
{
#region IEqualityComparer<Main> Members
public bool Equals( Main x, Main y )
{
return x.StringProperty == y.StringProperty;
}
public int GetHashCode( Main obj )
{
return obj.IntegerProperty.GetHashCode() ^ obj.StringProperty.GetHashCode();
}
#endregion
}
public class AllPropertiesEqualityCompare : IEqualityComparer<Main>
{
#region IEqualityComparer<Main> Members
public bool Equals( Main x, Main y )
{
return ( x.IntegerProperty == y.IntegerProperty ) && ( x.StringProperty == y.StringProperty );
}
public int GetHashCode( Main obj )
{
return obj.IntegerProperty.GetHashCode() ^ obj.StringProperty.GetHashCode();
}
#endregion
}
public abstract class Main
{
public int IntegerProperty { get; set; }
public string StringProperty { get; set; }
public bool Equals( IEqualityComparer<Main> comparer, Main other )
{
return comparer.Equals( this, other );
}
}
public class ConcreteA : Main
{ }
public class ConcreteB : Main
{ }
class TemporaryTest
{
public static void Run()
{
var a = new ConcreteA();
a.IntegerProperty = 1;
a.StringProperty = "some";
var b = new ConcreteB();
b.IntegerProperty = 1;
a.StringProperty = "other";
Console.WriteLine( a.Equals( new IntegerPropertyEqualityCompare(), b ) );
Console.WriteLine( a.Equals( new StringPropertyEqualityCompare(), b ) );
Console.WriteLine( a.Equals( new AllPropertiesEqualityCompare(), b ) );
}
}
Maybe then somthing like this?
I'm not sure that I understand what you want to do.
So I go with IComparable<T>.