I'm writing an iphone application with JSON and am trying to turn JSON strings into objects (NOT Dictionaries or Arrays).
In Java, thanks to Reflection, I can easily turn JSON into javabean instances like this:
import net.sf.json.JSONObject;
class MyBean {
private String property;
public String getProperty() { return property; }
public void setProperty(String property) { this.property=property; }
}
// turn JSON string into a MyBean instance
String str = "{\"property\":\"some value\"}";
JSONObject jsonObject = (JSONObject) JSONSerializer.toJSON( str );
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setRootClass( MyBean.class );
MyBean instance = (MyBean) JSONSerializer.toJava( jsonObject, jsonConfig );
I was wondering if this was possible in objective-c. I am currently using this JSON framework but am willing to switch if necessary.
Thanks,
There is an open source project called objectiveresource and objectivesupport. They are partial Objective-C implementations of a what is called ActiveResource and ActiveSupport in the Ruby and RESTful development world. Part of what objectivesupport does is serializing and deserializing JSON (as well as XML) object. If you don't want to use the full frameworks as is, you can take a look at the source code for objectivesupport and there you will see their implementation of serializing to/from an NSObject. The specific code you want to look at are listed below: (Basically implemented as a category on the NSObject, NSArray and NSDictionary types)
http://github.com/yfactorial/objectivesupport/tree/d08b5be6c0f7a2b0196b6ec17e4441bb146c4e23/Classes/lib/Serialization/JSON
BTW, they seem to be using a fork of the same JSON framework that you are using.
Maybe looking at the Objective-C Runtime Reference could help you !
There are some functions (like class_createInstance and object_setInstanceVariable) that could help you.
You might want to checkout my implementation for serializing and deseriazling JSON to NSObjects and vice versa. - https://github.com/mahadevans87/OBJC_JSONSerializer
Just in case anyone else gets here when looking for an answer to this question, there's another project that has exactly what you're looking for: JSON for iPhone, and nothing else.
Have a look at here
Related
I am studying Rest Assured framework now.
Using some API I get the following (partial) JSON response:
{
"results": [
{
"type": "AAAA"
},
{
"type": "A"
}
]
}
I am trying to verify the types.
The only way I found so far is to use gson to translate the string to an object and then assert:
#Given("^test2$")
public void test2$() {
RestAssured.baseURI = BASE_URI;
String response =
given()
.param(KEY_KEY, API_KEY)
.param(URL_KEY, URL_TO_CHECK)
.when()
.get(RESOURCE)
.asString();
System.out.println(response);
GsonBuilder builder = new GsonBuilder();
builder.setPrettyPrinting();
Gson gson = builder.create();
WhtResponse whtResponse = gson.fromJson(response, WhtResponse.class);
assertTrue(whtResponse.getResults().size() == 2);
assertTrue(whtResponse.getResults().get(0).getType().equals("AAAA"));
assertTrue(whtResponse.getResults().get(1).getType().equals("A"));
}
Please ignore that there are several asserts in one test method. I know it is not best practice but I am just "playing" now to study the material.
Is there a better, shorter, more fluent way to test both values? Maybe directly with Rest Assured and without the Gson?
Thanks!
There are probably a few ways but I want to present a specific one, using only RestAssured.
First, of all, you can create Java classes to represent the given JSON. You can always expand it.
Create a class ResultsObject (name doesn't matter)
public class ResultsObject {
public List<TypeObject> results;
}
We are declaring that RestAssured have to look for a JSON Array of JSON Objects. Each of these Object is parsed to TypeObject (this name also doesn't matter). What matters, is the results variable name. It matches the results in the JSON.
So, now we have to create TypeObject class to represent each of JSON Objects.
public class TypeObject {
public String type;
}
Again, the class name doesn't matter, what matters is type variable name. Just like in JSON.
Now, with a single line of code we can parse the JSON (either from Response or String) to the classes we created like this:
ResultsObject results = response.jsonPath().get("$", ResultObject.class);
Further work requires to create an assertion.
MatcherAssert.assertThat(types, Matchers.hasItems("AAAA", "A")); //you can use static imports if you'd like.
The assertion is from Hamcrest which is already included in RestAssured. It matches the Array of Strings to an Array of Strings of our choice.
You can notice, that types is not yet initialized. We need an Array of Strings but it's an Array of TypeObject. We can simply convert it using Java Stream API like this:
List<String> types = resultsObject.results.stream().map(x -> x.type).collect(Collectors.toList());
And that's it!
But the way, if you get the Exception like this Cannot deserialize object because no JSON deserializer found in classpath. Please put either Jackson (Databind) or Gson in the classpath. all you have to do is add jackson-databind to Maven. Rest Assured is able to use Gson or Jackson databind to transform JSON into Java classes.
All you need is the dependency, and you are all set.
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.9</version>
</dependency>
I already tested the solution.
It also gives you the flexibility of how you want to process the data, and as you can see, I used only 1 Assertion to compare all of the types from JSON.
Hope it helps!
Scenario: I have a GWT web application running within a JavaFX WebView/WebEngine. I am able to pass Strings from GWT to JavaScript to JavaFX without any issues.
Problem: When passing an array of custom objects like Data[] in the same fashion, the result on the JavaFX side is null.
An example of what Data looks like:
public class Data extends Serializable
{
char[] name;
int code;
short bar;
}
Here's the code to send the data to JavaScript:
public static native void doNativeStuff(String id, Data[] data) /*-{
$wnd.javaInterface.doStuff(id, data);
}-*/;
I've verified in the debugger that the Java object being passed in is populated with data and looks good.
Now on the JavaFX side, I have the following code to add the javaInterface to the page:
JSObject win = (JSObject) engine.executeScript("window");
win.setMember("javaInterface", new JavaInterface());
I know that this works because I'm using it for other methods that pass only Strings and they work great.
public void doStuff(String id, Data[] data)
{
// Right here, id == "validId" and data == null
if (data != null)
{
... do what is needed ...
}
}
Note that the Data object is defined and accessible on both sides.
From the GWT documentation:
Incoming Java type How it appears to JavaScript code
Java array opaque value that can only be passed back into Java code
I'm not touching it in JavaScript at all and I'm only passing it through from Java->JavaScript->Java, but the final step appears to be what is failing.
I've spent the last few hours scouring Stack Overflow, Google, GWT groups, gwtproject.org, etc. But most all of the examples only show a single argument being passed through and almost none of them show a Java Array being used.
I'd much rather just pass the object through rather than going to->from JSON, but I did give that a try out of desperation. I tried to use GSON but it doesn't work on the GWT client side. I tried to use the GWT AutoBean Framework but my Data object isn't a valid bean (I think because of no default constructor) and I cannot change that at this time.
I'm not using any Long or long values.
I've seen examples like this:
#com.google.gwt.examples.JSNIExample::staticFoo(Ljava/lang/String;)(s);
But from what I can tell that's just for going from JavaScript to GWT over JSNI. I'm trying to go the other way. I also couldn't find an example of this for multiple arguments.
I'm sure that there is just a minor tweak here that I'm missing, but I haven't been able to figure it out just yet. Please let me know if you see something that I'm missing here.
opaque value that can only be passed back into Java code
I think this means you cannot pass Java array into JavaScript code.
Agree with jat. I used to provide support for the similar needs and I had to serialize the objects myself.
And you can pass multiple arguments like this (types of arguments are given just for example):
private native void doJSAction(MyClass handler)/*-{
// do smth in JS
// then call external non-static method
handler.#com.myclient.helper.MyClass::doMyAction(Lcom/google/gwt/core/client/JavaScriptObject;Ljava/lang/String;Lcom/myclient/helper/MyClass;II)(jsNativeSmth, myString, handler, intA, intB);
}-*/;
where doMyAction is something like the following:
void doMyAction(JavaScriptObject jsObject, String s, MyClass instance, int a, int b)
I haven't played with JavaFX, but since it runs in a different VM and knows nothing about the GWT DevMode protocol (for example, a Java object is wrapped in a JS object that basically makes RPC calls to manipulate it), I am pretty sure you are going to have to serialize everything between GWT and JavaFX as Strings and primitives.
In Guvnor documentation, I know how to define data enumeration and use it in Guvnor. Is it possible to fetch data enumeration from my own Java code?
From Guvnor's documentation:
Loading enums programmatically: In some cases, people may want to load their enumeration data entirely from external data source (such as a relational database). To do this, you can implement a class that returns a Map. The key of the map is a string (which is the Fact.field name as shown above), and the value is a java.util.List of Strings.
public class SampleDataSource2 {
public Map<String>, List<String> loadData() {
Map data = new HashMap();
List d = new ArrayList();
d.add("value1");
d.add("value2");
data.put("Fact.field", d);
return data;
}
}
And in the enumeration in the BRMS, you put:
=(new SampleDataSource2()).loadData()
The "=" tells it to load the data by executing your code.
Best Regards,
I hope its not too late to answer this.
To load enum from application to guvnor,
Build the enum class dynamically from string (in my case enum values is provided by user via GUI)
Add it to a jar, convert it to byte array
POST it to guvnor as asset (model jar) via REST call
Call save repository operation (change in source code of guvnor)
Now enum will be visible as fact in your rule window.
Editing/Deletion of model jar and validation of rules aftermath is something you have to take care.
In my app I use JsArray extensively to store my overlay types. I use java.util.List to store my client-side Java POJOs.
For performance reasons and to unify the way I access my model I planned to eliminate the Lists and use only JSO wrappers. Given a wrapper around a native array that can store any Java Object:
public class JsArrayObject<T> extends JavaScriptObject {
protected JsArrayObject() {}
public final native T get(int index) /*-{
return this[index];
}-*/;
public final native void push(T value) /*-{
this[this.length] = value;
}-*/;
}
Is it safe to store Java Objects this way? The doc says that when you pass a Java Object into JavaScript the result is "an opaque value accessible through special syntax". This sounds confussing to me. For instance if I push an Integer and try to get it an exception will be thrown because something different than an Object was found (at least in dev mode). The same happens with the rest of Java primitive Wrappers. Apart from the problems with Java primitive Wrappers, are there other concerns to be aware?
Many thanks
Which doc are you referring to? The one on this page?
They're talking in terms of passing Java objects into JavaScript with the intent of having JavaScript code use the methods or fields in the object. It is possible to do that, but the syntax you have to use on the JavaScript side is a bit awkward. If you've done any JSNI, you've seen it.
If you don't intend to access the Java objects from the JavaScript side you can ignore the business about the special syntax. So yes, it is safe. I'd be interested to know if it actually turns out to help performance.
For my iPhone app, I'm consuming a RESTful service and getting JSON. I've found libraries to deserialize this into an NSDictionary. However, I'm wondering if there are any libraries to deserialize the JSON/NSDictionary/Property List into my object (an arbitrary one on my side).
The java equivalent would be the object-relational mappers although the sort of object mapping I'm looking for is relatively straightforward (simple data types, no complex relationships, etc.).
I noticed that Objective-C does have introspection so it seems theoretically possible but I haven't found a library to do it.
Or is there a simple way to load an object from an NSDictionary/Property List object that doesn't require modification every time the object changes?
For example:
{ "id" : "user1",
"name" : "mister foobar"
"age" : 20 }
gets loaded into object
#interface User : NSObject {
NSString *id;
NSString *name;
int *age;
}
Take a look at the NSKeyValueCoding protocol. In particular, the methods setValuesForKeysWithDictionary: and dictionaryWithValuesForKeys:
I've made a framework to do this automatically. Check out.
https://github.com/dchohfi/KeyValueObjectMapping
Take a look at the Loid project on Sourceforge. My intent is to provide what you are talking about.
Right now the framework can reverse engineer a Meta description about an Object (such as your "User" object) and can serialize to and from a LoidTypeData object. My intent is to create a LoidTypeData instance from an incoming JSON block and then bind it to the Object. Of course, the reverse will also be there.
It is open source and GPL. You will need to access the code from SVN at the moment, don't quite know how to build distro for Mac.
-- Frank