The differences between the following 2 cases are
a> The type of variable 'arr'. In the first case, its type is Integer[], while in the second case its type is int[].
b> We can see from where I marked as "// here" that in the case 1 it needs Integer[][][]. while in the case 2 it needs int[][].
Both of case 1 and case 2 work. So my question comes:
Why Junit require I return a 3-dimentional Integer array in the data() method in case 1 when the test data is a 1-dimentional Integer array.
I expected it should be 2 - dimentional Integer array because in the case 2 I return a 2 - dimentional int array in the data() method and it is easy to understand it and it works. But when I tried to return 2-dimentional Integer array in the data() method in case 1 as
#Parameterized.Parameters(name = "test with {index}")
public static Iterable<Integer[]> data() {
return Arrays.asList(new Integer[][]{
{3, 1, 4, 6, 7, 9},
{9, 8, 7, 6, 5, 4},
});
}
Junit reported "java.lang.IllegalArgumentException: wrong number of arguments". Please help me if you know the reason.
I searched Junit documents and many other pages without satisfied answer.
Please help.My Junit version is 4.12.
case 1
#RunWith(Parameterized.class)
public class MyTest {
#Parameterized.Parameters(name = "test with {index}")
public static Iterable<Integer[][]> data() {
//here: My question is why it can not be Integer[][]
return Arrays.asList(new Integer[][][]{
{{3, 1, 4, 6, 7, 9}},
{{9, 8, 7, 6, 5, 4}},
});
}
private Integer[] arr;
public MyTest(Integer[] arr) {
this.arr = arr;
}
public methodTest(int[] arr) {
// ignore the code here
}
}
case 2
#RunWith(Parameterized.class)
public class MyTest {
#Parameterized.Parameters(name = "test with {index}")
public static Iterable<int[]> data() {
//here int[][] works
return Arrays.asList(new int[][]{
{3, 1, 4, 6, 7, 9},
{9, 8, 7, 6, 5, 4},
}
private int[] arr;
public MyTest(int[] arr) {
this.arr = arr;
}
public methodTest(int[] arr) {
// ignore the code here
}
}
Data itself should always be the same type as data expected by constructor, not by test. Also you've got a bit lost between structure of data() and the data itself. I prefer the following structure, it clearly expresses what we need:
#Parameters
public static Collection<Object[]> data()
{
return Arrays.asList(
new Object[][]
{
{/* case 1*/},
{/* case 2*/},
}
);
}
Maybe this is not the shortest way, but you will never get lost with it, even with complex data. Every line here, except for /* case 1*/ and /* case 1*/ never changes. On top level we have a collection of arrays (of type object) and we create this collection by providing a 2-dimentional array of objects, with each row expressing test case.
So your Case 1 will become
#Parameterized.Parameters(name = "test with {index}")
public static Collection<Object[]> data() {
return Arrays.asList(
new Object[][]
{
{new Integer[]{3, 1, 4, 6, 7, 9}}, // here
{new Integer[]{9, 8, 7, 6, 5, 4}}, // here
}
);
}
and Case 2 will become
#Parameterized.Parameters(name = "test with {index}")
public static Collection<Object[]> data() {
return Arrays.asList(
new Object[][]
{
{new int[]{3, 1, 4, 6, 7, 9}}, // here
{new int[]{9, 8, 7, 6, 5, 4}}, // here
}
);
}
You also need to fix a couple of other problematic lines in your code, e.g. lack of return type on the test. Here's an example of complete runnable and passing test:
package x;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
#RunWith(Parameterized.class)
public class MyTest
{
#Parameterized.Parameters(name = "test with {index}")
public static Collection<Object[]> data() {
return Arrays.asList(
new Object[][]
{
{new Integer[]{3, 1, 4, 6, 7, 9}}, // here
{new Integer[]{9, 8, 7, 6, 5, 4}}, // here
});
}
private Integer[] arr;
public MyTest(Integer[] arr) {
this.arr = arr;
}
#Test
public void methodTest() {
// test some logic
System.out.println(arr.length);
}
}
The reason your Integer version requires more dimensions than the int version is that the first Iterable is Iterable<Integer [][]> which has one more dimension than the second one, Iterable<int[]>.
Related
I get the error:
Exception in thread "main" com.google.gson.JsonParseException:
Expecting object found: "com.shagie.app.SimpleMap$Data#24a37368"
when trying to deseralize a Map that uses non-trivial keys:
package com.shagie.app;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.HashMap;
public class SimpleMap {
public static void main(String[] args) {
Wrapper w = new Wrapper();
w.m.put(new Data("f", 1), new Data("foo", 3));
w.m.put(new Data("b", 2), new Data("bar", 4));
GsonBuilder gb = new GsonBuilder();
gb.setPrettyPrinting();
Gson g = gb.create();
String json = g.toJson(w);
System.out.println(json);
w = g.fromJson(json, Wrapper.class);
System.out.println(w.m.isEmpty());
}
static public class Wrapper {
HashMap<Data, Data> m = new HashMap<Data, Data>();
}
static public class Data {
String s;
Integer i;
public Data(String arg, Integer val) { s = arg; i = val; }
}
}
This serializes to the json:
{
"m": {
"com.shagie.app.SimpleMap$Data#24a37368": {
"s": "foo",
"i": 3
},
"com.shagie.app.SimpleMap$Data#66edc3a2": {
"s": "bar",
"i": 4
}
}
}
One can see the key attempting to be serialized, but certainly not in a way that can be deserialized.
How does one serialize this object so that it can be deserialized?
I found the following while trying to solve this puzzle: Issue 210: Cannot serialize or deserialize Maps with complex keys.
For any internet travelers from the future (like myself)... you can enable this functionality in GSON 2.* with the enableComplexMapKeySerialization() method on GsonBuilder.
Here's the javadoc for that method.
When enabled, the map will be serialized (and correctly deserialized) as an array of [key, value] arrays:
{"m":[[{"s":"f", "i",1}, {"s":"foo", "i":3}], [{"s":"b", "i",2}, {"s":"bar", "i":4}]]}
The problem is that toString() is getting called on the keys to the map, rather than them being serialized themselves.
To fix this a custom serializer and deserializer needs to be set up, and the deserializer needs to be aware of the format that the object uses to display itself as a string (the toString() method must return a string that can be used to reconstruct the entire object).
For the above example:
package com.shagie.app;
import com.google.gson.*;
import java.lang.reflect.Type;
import java.util.HashMap;
public class SimpleMapFixed {
public static void main(String[] args) {
Wrapper w = new Wrapper();
w.m.put(new Data("f", 1), new Data("foo", 3));
w.m.put(new Data("b", 2), new Data("bar", 4));
GsonBuilder gb = new GsonBuilder();
gb.setPrettyPrinting();
gb.registerTypeAdapter(Data.class, new DataSerializer());
Gson g = gb.create();
String json = g.toJson(w);
System.out.println(json);
w = g.fromJson(json, Wrapper.class);
System.out.println(w.m.isEmpty());
}
static public class Wrapper {
HashMap<Data, Data> m = new HashMap<Data, Data>();
}
static public class DataSerializer implements JsonSerializer<Data>,
JsonDeserializer<Data> {
#Override
public Data deserialize(JsonElement je, Type t, JsonDeserializationContext ctx)
throws JsonParseException {
Data rv;
JsonObject jo;
System.out.println("deserialize called with: " + je.toString());
if (je.isJsonObject()) {
jo = je.getAsJsonObject();
rv = new Data(jo.get("s").getAsString(), jo.get("i").getAsInt());
} else {
String js = je.getAsString();
String[] s = js.split(":", 2); // split into two (and only two)
rv = new Data(s[1], Integer.valueOf(s[0]));
}
System.out.println("deserialize returns: " + rv.s + " " + rv.i);
return rv;
}
#Override
public JsonElement serialize(Data data, Type type, JsonSerializationContext jsonSerializationContext) {
JsonObject jo = new JsonObject();
jo.addProperty("s", data.s);
jo.addProperty("i", data.i);
System.out.println("serialize called: " + jo.toString());
return jo;
}
}
static public class Data {
String s;
Integer i;
public Data(String arg, Integer val) { s = arg; i = val; }
#Override
public String toString() {
String rv = i.toString() + ':' + s;
System.out.println("toString called: " + rv);
return rv;
}
}
}
Running this code produces:
serialize called: {"s":"foo","i":3}
toString called: 1:f
serialize called: {"s":"bar","i":4}
toString called: 2:b
{
"m": {
"1:f": {
"s": "foo",
"i": 3
},
"2:b": {
"s": "bar",
"i": 4
}
}
}
deserialize called with: "1:f"
deserialize returns: f 1
deserialize called with: {"s":"foo","i":3}
deserialize returns: foo 3
deserialize called with: "2:b"
deserialize returns: b 2
deserialize called with: {"s":"bar","i":4}
deserialize returns: bar 4
Note the invocations of toString() as part of the serialization. In this code, the logic for the deserializion from the String form is in the DataSerializer, though it may make sense to move it into the Data class as another constructor instead - it doesn't affect the final outcome.
Further note that Data was a rather simple object itself with no deeper structures. Trying to serialize that as the key would require additional work.
Its Up to you how you are maintaining the HahMap Keys, You can deserialized it with simple and easiest way.
final Type typeOf = new TypeToken <Map<String, Map<String, Data>>>(){}.getType();
final Map<String, Map<String, Data>> newMap = gson.fromJson(json, typeOf);
final Map<String, Data> map = newMap.get("m");
final Iterator<Entry<String, Data>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String,Data> pair = (Map.Entry<String,Data>) it.next();
String key = pair.getKey();
System.out.println("key "+ key + " Values[ i= " + data.getI() + ", s= " +data.getS()+" ]");
}
Result:
key = snippet.Snippet$Data#61506150 Values [ i= 3, s= foo ]
key = snippet.Snippet$Data#63ff63ff Values [ i= 4, s= bar ]
My project is to processing data from my database. I got an input text for entering xml data(plain text format), this part works but now I need to process this data to extract the words I need and push them into a Graph (vis.js). I'm using spring-boot 2.1.4 and angular 8. Thanks in advance for investigating ! love
I'have not trying anything, I only searched in the web. But I need you for guide me. If you have source or anything. It could be nice !
I tried this in google : "data processing spring boot angular"
and this : creating-rest-api-using-spring-boot
My database
In springboot:
My Graph.java:
#Entity(name = "graphiques")
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Graph {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name ="id")
private Long id;
#Column(name ="xml")
private String xml;
#Override
public String toString() {
return "GraphQuery{" +
"id" + id +
", xml ='" + xml + '\'' +
'}';
}
}
My GraphRepository.java:
#Repository
public interface GraphRepository extends CrudRepository<Graph, Long> {
}
My GraphController.java:
#RestController
#RequestMapping(value = "/graph")
#ResponseStatus(HttpStatus.CREATED)
public class GraphController {
private GraphRepository graphRepository;
#Autowired
GraphController(GraphRepository graphRepository){
this.graphRepository = graphRepository;
}
#PostMapping
public Graph post(#RequestBody Graph graph){
return this.graphRepository.save(graph);
}
//Ajout du xml dans la base
#GetMapping("/{graph_id}")
public Optional<Graph> get(#PathVariable Long graph_id) {
return this.graphRepository.findById(graph_id);
}
In angular:
My graph.component.ts
#ViewChild('siteConfigNetwork', { static: true }) networkContainer: ElementRef;
constructor() { }
ngOnInit() {
this.initGraph();
}
initGraph() {
let nodes = [
{ id: 1, label: 'Node 1' },
{ id: 2, label: 'Node 2' },
{ id: 3, label: 'Node 3' },
{ id: 4, label: 'Node 4' },
{ id: 5, label: 'Node 5' }
];
let edges = [
{ from: 1, to: 3 },
{ from: 1, to: 2 },
{ from: 2, to: 4 },
{ from: 2, to: 5 }
];
let container = this.networkContainer.nativeElement;
let data = {
nodes: nodes,
edges: edges
}
let options = {};
let network = new vis.Network(container, data, options);
}
I want my data be linked when multiple tag("to" and "from") are in one tag("note"). So the tag note will be the node and edges must start from this node and be linked to the node "to" and "from".
I don't know if I'm clear. Be indulgent I'm a little french who begin's in dev.
Thank's again for helping me !
Please look at the below code. I expect the result of the serialization to be:
{
"origin": {
"x": 1,
"y": 2
},
"size": {
"width": 3,
"height": 4
}
}
Instead it is
{
"origin": {
"a": 1,
"b": 2
},
"size": {
"a": 3,
"b": 4
}
}
How can I make json2typescript to use the name of the properties in the Coord and Size classes instead of using the name of the properties in the (common) base class Pair?
I tried to remove the #Json decorations from Pair but then nothing in Coord and Size is serialized.
#JsonObject("Pair")
export class Pair2
{
#JsonProperty("a", Number)
protected a: number;
#JsonProperty("b", Number)
protected b: number;
constructor(a?: number, b?: number)
{
this.a = a;
this.b = b;
}
}
#JsonObject("Coord")
export class Coord2 extends Pair2
{
#JsonProperty("x", Number)
public get x(): number { return this.a; }
public set x(value: number) { this.a = value; }
#JsonProperty("y", Number)
public get y(): number { return this.b };
public set y(value: number) { this.b = value };
constructor(x?: number, y?: number)
{
super(x, y);
}
}
#JsonObject("Size")
export class Size2 extends Pair2
{
#JsonProperty("width", Number)
public get width(): number { return this.a; }
public set width(value: number) { this.a = value; }
#JsonProperty("height", Number)
public get height(): number { return this.b };
public set height(value: number) { this.b = value };
constructor(width?: number, height?: number)
{
super(width, height);
}
}
#JsonObject("Rectangle")
export class Rectangle2
{
#JsonProperty("origin", Coord2)
origin: Coord2;
#JsonProperty("size", Size2)
size: Size2;
constructor(origin: Coord2, size: Size2)
{
this.origin = origin;
this.size = size;
}
}
let jsonConvert: JsonConvert = new JsonConvert();
jsonConvert.operationMode = OperationMode.LOGGING; // print some debug data
jsonConvert.ignorePrimitiveChecks = false; // don't allow assigning number to string etc.
jsonConvert.valueCheckingMode = ValueCheckingMode.DISALLOW_NULL; // never allow null
let origin = new Coord2(1, 2);
let size = new Size2(3, 4);
let rectangle = new Rectangle2(origin, size);
let rectangleJsonObj = jsonConvert.serialize(rectangle);
console.log(rectangleJsonObj);
let rectangleStr = JSON.stringify(rectangleJsonObj);
console.log(rectangleStr);
The way I fixed the issue is:
Instead of using the json2typescript library I used JSON.stringify and JSON.parse
I used toJSON() to return an object that has width and height as below:
private toJSON = () =>
{
return {
width: this.width,
height: this.height
}
}
I'm learning grails with json and I encountered this problem, which my JSON duplicate 4x in the same object and should be each, not all together:
[{"id":[2,1,4,3],"address":"[test.web.Address : 2, test.web.Address : 1, test.web.Address : 4, test.web.Address : 3]","range":[300,200,500,400],"placetype":"[Dangerous, Dangerous, Dangerous, Dangerous]"},{"id":[2,1,4,3],"address":"[test.web.Address : 2, test.web.Address : 1, test.web.Address : 4, test.web.Address : 3]","range":[300,200,500,400],"placetype":"[Dangerous, Dangerous, Dangerous, Dangerous]"},{"id":[2,1,4,3],"address":"[test.web.Address : 2, test.web.Address : 1, test.web.Address : 4, test.web.Address : 3]","range":[300,200,500,400],"placetype":"[Dangerous, Dangerous, Dangerous, Dangerous]"},{"id":[2,1,4,3],"address":"[test.web.Address : 2, test.web.Address : 1, test.web.Address : 4, test.web.Address : 3]","range":[300,200,500,400],"placetype":"[Dangerous, Dangerous, Dangerous, Dangerous]"}]
My domain Address:
Long id
String street
String city
Long zip;
int number
My domain Place:
Long id
Long range
PlaceType type
Address address
My Controller:
def avoid() {
def result = [];
def r = []
def a = Place.executeQuery("select distinct a from Place a where a.type = 1")
for (int i = 0; i < a.size(); i++) {
println(result)
result.add(a)
}
if (result) {
result.each() { place ->
r << [id: place.id,
address: place.address.street.toString(),
range: place.range,
placetype: place.type.toString()
];
}
} else {
println('error')
}
return jsonRender("JSON", params.callback, r)
}
PlaceType enum
enum PlaceType {
DANGEROUS('Dangerous', 1),
NOT_DANGEROUS('Not Dangerous', 2)
private final int id;
private final String description;
public PlaceType(String description, int id) {
this.description = description
this.id = id
}
public static PlaceType getById(int id) {
switch (id) {
case 1:
return DANGEROUS
case 2:
return NOT_DANGEROUS
}
}
#Override
public String toString() {
description
}
public short getId() {
id
}
}
Where I'm doing wrong? edit: test.web.Address now show the real address
there is a lot of "noise" in your groovy code...
I'd put it like that:
def avoid(){
render Place.findAllByType( PlaceType.Dangerous ).collect{ Place place ->
[id: place.id,
address: place.address.street.toString(),
range: place.range,
placetype: place.type.toString()
]
} as JSON
}
In this case you have a couple of possible error sources fewer.
Also I think, that stuff like place.type.toString() is wrong. The object shall be JSON-ified directly and the output should be a JSON-object rather that default toString() implementation
I don't know the method
jsonRender ("JSON", params.callback, r)
Please try this:
render r as JSON
and don't forget the import:
import grails.converters.*
see doc for render method: http://grails.org/doc/latest/ref/Controllers/render.html
or try to use the new response method: http://grails.org/doc/latest/ref/Controllers/respond.html
I am building an app that uses Open Flash Chart 2. This chart is a flash object that accepts JSON with a specific structure.
"elements": [
{
"type": "bar_stack",
"colours": [
"#F19899",
"#A6CEE3"
],
"alpha": 1,
"on-show": {
"type": "grow-up",
"cascade": 1,
"delay": 0
},
...
I am using a simple anonymous type to return the JSON like so:
return Json(new
{
elements = new [] {
new
{
type = "bar_stack",
colours = colours.Take(variables.Count()),
alpha = 1,
on_show = new
{
type = "grow-up",
cascade = 1,
delay = 0
},
...
}
}
The problem is that several properties (like "on-show") use a dash and obviously I cannot use a dash when naming a property in C# code.
Is there a way to overcome this? Preferably without the need to declare a whole bunch of classes.
You can use a dictionary:
return Json(new {
elements = new [] {
new Dictionary<string, object>
{
{ "type", "bar_stack" },
{ "colours", new [] { "#F19899", "#A6CEE3" } },
{ "alpha", 1 },
{ "on-show", new
{
type = "grow-up",
cascade = 1,
delay = 0
} },
}
}
});
(Written in SO editor; I may have made some syntax errors, but you get the idea....)
Craig's solution is propably better, but in the meantime I implemented this:
public class UnderscoreToDashAttribute : ActionFilterAttribute
{
private readonly string[] _fixes;
public UnderscoreToDashAttribute(params string[] fixes)
{
_fixes = fixes;
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.HttpContext.Response.Filter = new ReplaceFilter(filterContext, s => _fixes.Aggregate(s, (current, fix) => current.Replace(fix, fix.Replace('_', '-'))));
}
public class ReplaceFilter : MemoryStream
{
private readonly Stream _stream;
private readonly Func<string, string> _filter;
public ReplaceFilter(ControllerContext filterContext, Func<string, string> filter)
{
_stream = filterContext.HttpContext.Response.Filter;
_filter = filter;
}
public override void Write(byte[] buffer, int offset, int count)
{
// capture the data and convert to string
var data = new byte[count];
Buffer.BlockCopy(buffer, offset, data, 0, count);
var s = _filter(Encoding.Default.GetString(buffer));
// write the data to stream
var outdata = Encoding.Default.GetBytes(s);
_stream.Write(outdata, 0, outdata.GetLength(0));
}
}
}
Then, if you decorate your action like so:
[UnderscoreToDash("on_show", "grid_colour")]
public JsonResult GetData()
It makes the appropriate "fixes".
P.S. That awesome moment when Resharper changes your code to Linq...
_fixes.Aggregate(s, (current, fix) => current.Replace(fix, fix.Replace('_', '-')))