GWT Overlay Tpes check for null - gwt

I'm using GWT overlay types to parse my JSON response form the web server. It all works fine, the problem is, if the required field doesn't exist:
example:
JavaScriupt overlay type class
public class JSWorkplace extends JavaScriptObject{
protected JSWorkplace() {
}
public final native String getWidgets() /*-{
return this.Widgets;
}-*/;
now if I have something like {"Widgets":"Bla"} comes form the server everything is alright, getWidgets returns "Bla".
If this "{}" comes from the server my application throws in the gwtWidgets function. How can I check if the field "Widgets" exists before reading it.
Regards,
Stefan

You can check if it's undefined doing something like: this.Widgets == undefined.
Personally I prefer to set default values after the eval(). For example, in order to create your JSWorkplace object I would invoke a method like this:
public static native JSWorkspace createFromJSON(String json)/*-{
var object = eval('(' + json + ')');
if (object.Widgets == undefined) { object.Widgets = []; }
...
return object;
}*-/;

Related

Jackson and REST Android Annotations: Deserialize JSON Array of Objects

I have a REST service which returns data that looks like this:
[
{ bookmark object json here },
{ bookmark object json here },
{ bookmark object json here },
...
]
My REST client class looks like this:
#Rest(rootUrl = Constants.ApiConfig.API_ROOT, converters = {MappingJackson2HttpMessageConverter.class})
public interface RestApiClient {
#Get("/bookmark/read?id={identifier}")
public BookmarkList getBookmarks(String identifier);
}
BookmarkList looks like this:
public class BookmarkList {
List<Bookmark> bookmarks;
#JsonValue
public List<Bookmark> getBookmarks() {
return bookmarks;
}
#JsonCreator
public void BookmarkList(#NotNull List<Bookmark> bookmarks) {
this.bookmarks = bookmarks;
}
}
However, when I utilize this setup, I get the following error:
Could not read JSON: Can not deserialize instance of com.whatever.entity.BookmarkList out of START_ARRAY token
What I want is something like the EventList example at https://github.com/excilys/androidannotations/wiki/Rest-API#get, but that doesn't seem to work for me out of the box.
Is there a way to get this working?
Ho... We have to update this part of documentation. The wrapper solution works but doesn't fit APIs.
If you're looking at the generated code for #Get("url") MyReturnedType testService(), you should see something like this :
return restTemplate.exchange(rootUrl.concat("url"), //
HttpMethod.GET, //
null, //
MyReturnedType.class, //
urlVariables)//
.getBody();
The returned class is injected as a parameter of exchange call. In case of generics collection (like List<MyReturnedType>), we can't inject List.class because of type checking in the return of exchange method.
However, you should be able to use this little trick in your #Rest annotated method :
public class BookmarkList extends List<Bookmark> {
}
I think I misunderstood the example at https://github.com/excilys/androidannotations/wiki/Rest-API#get. I think the array still must be wrapped inside a JSON object in that example (It'd be nice if they included example JSON data).
The data the service I'm connecting to does not return an object wrapping the array like that, so, I altered the REST client to look like this:
#Rest(rootUrl = Constants.ApiConfig.API_ROOT, converters = {MappingJackson2HttpMessageConverter.class})
public interface RestApiClient {
#Get("/bookmark/read?id={identifier}")
public ArrayNode getBookmarks(String identifier);
}
And I wrote a method in another class to iterate the ArrayNode and build the bookmarks:
public List<Bookmark> getBookmarks(Content content) {
ArrayList<Bookmark> bookmarks = new ArrayList<Bookmark>();
ArrayNode bookmarksData = apiClient.getBookmarks(content.getAcid());
for(JsonNode bookmarkData : bookmarksData) {
Bookmark bookmark = objectMapper.convertValue(bookmarkData, Bookmark.class);
bookmarks.add(bookmark);
}
return bookmarks;
}
So it's not as convenient (I had to write more code myself), but I got it working.

How to implement a javascript API using JSNI?

I am trying to implement an API (SCORM API) using GWT.
The client code expects an API object with methods like Initialize(), getLastError() and so on...
I tried to implement this api as an Java Object, but i see that the compiled names are changed and cannot be used directly by client code.
I see that gwt-exporter can do the trick (http://code.google.com/p/gwt-exporter/) but i would like to know how to do it using pure gwt and jsni.
As the API is expected as a object, named API_1484_11 attached to the window object, not an function, , i don't see how to use the $entry() idiom.
Here is my current, failing, code:
public final class SCORMApi {
protected SCORMApi() {}
public void Initialize(){
GWT.log("** INITIALIZE CALLED **");
}
public static void create(){
bind(new SCORMApi());
}
public static native void bind(SCORMApi api) /*-{
$wnd.API_1484_11 = api;
}-*/;
}
So, in this context, my question is:
How can i get javascript calls (e.g. window.API_1484_11.Initialize() ) to reach my java gwt code?
You're on the right lines with your bind method. But you haven't understood how to call Java methods from within JSNI. This is how you do it in the case of your Initialize method:
public static native void bind(SCORMApi api) /*-{
$wnd.API_1484_11 = {
initialize: function() {
$entry( api.#com.yourpackage.name.SCORMApi::Initialize()() );
}
};
}-*/;
The blogs Getting To Really Know GWT parts 1 and 2 are required reading on this subject.

Passing javascript parameter from external javascript to java

An external javascript gives a number that should be handed over to Java method named mycallback.
I have defined:
Java:
class MyClass {
public static void mycallback(JavaScriptObject number) {
// do something with the number
}
}
Javascript:
$wnd.callback = $entry(#com.package.MyClass::mycallback(Lcom/google/gwt/core/client/JavaScriptObject));
And the Javascript call is:
$wnd.callback(number_from_external_javascript);
But I get error:
JS value of type number, expected com.google.gwt.core.client.JavaScriptObject
And my ultimate goal is to have a java method with parameter type of Integer, not of JavascriptObject. I just thought GWT should wrap javascript objects in JavascriptObject, but it seems it won't.
GWT version is 2.4.
GWT will automatically cast a JS Number value to any Java number primitive type (int, double, etc.), JS String to Java String, and JS Boolean to Java boolean. It'll never pass them as JavaScriptObjects.
If the number cannot be null, then just declare your callback with an int argument. If it can be null, then you'll have to explicitly create an Integer instance, something like:
$wnd.callback = $entry(function(n) {
if (number != null) {
// box into java.lang.Integer
number = #java.lang.Integer::valueOf(I)(n);
}
#com.packge.MyClass::mycallback(Ljava/lang/Integer;)(number);
});
Alternatively, I think you can pass a JS number as a JavaScriptObject if it's a Number object rather than a Number value, so this might work:
$wnd.callback = $entry(function(n) {
n = new Number(n); // "box" as a Number object
#com.packge.MyClass::mycallback(Lcom/google/gwt/core/client/JavaScriptObject;)(n);
});
What about using the gwt-exporter generator to expose your gwt code to js, so you dont have to deal with jsni and you could benefit of the nice features it has (complex objects, arrays, closures, overlays, doclet, etc)
Using gwt-exporter your class just have to implement Exportable and use an annotation to expose your method.
public static class MyClass implements Exportable {
#Export("$wnd.mycallback")
public static void mycallback(long number) {
Window.alert("" + number);
}
}
Add this line to your onmoduleload and leave the compiler to do the work
public void onModuleLoad() {
ExporterUtil.exportAll();
}
Then you can use the method as you said
<script>
window.mycallback(1234)
</script>

How to handle optional query parameters in Play framework

Lets say I have an already functioning Play 2.0 framework based application in Scala that serves a URL such as:
http://localhost:9000/birthdays
which responds with a listing of all known birthdays
I now want to enhance this by adding the ability to restrict results with optional "from" (date) and "to" request params such as
http://localhost:9000/birthdays?from=20120131&to=20120229
(dates here interpreted as yyyyMMdd)
My question is how to handle the request param binding and interpretation in Play 2.0 with Scala, especially given that both of these params should be optional.
Should these parameters be somehow expressed in the "routes" specification? Alternatively, should the responding Controller method pick apart the params from the request object somehow? Is there another way to do this?
Encode your optional parameters as Option[String] (or Option[java.util.Date], but you’ll have to implement your own QueryStringBindable[Date]):
def birthdays(from: Option[String], to: Option[String]) = Action {
// …
}
And declare the following route:
GET /birthday controllers.Application.birthday(from: Option[String], to: Option[String])
A maybe less clean way of doing this for java users is setting defaults:
GET /users controllers.Application.users(max:java.lang.Integer ?= 50, page:java.lang.Integer ?= 0)
And in the controller
public static Result users(Integer max, Integer page) {...}
One more problem, you'll have to repeat the defaults whenever you link to your page in the template
#routes.Application.users(max = 50, page = 0)
In Addition to Julien's answer. If you don't want to include it in the routes file.
You can get this attribute in the controller method using RequestHeader
String from = request().getQueryString("from");
String to = request().getQueryString("to");
This will give you the desired request parameters, plus keep your routes file clean.
Here's Julien's example rewritten in java, using F.Option: (works as of play 2.1)
import play.libs.F.Option;
public static Result birthdays(Option<String> from, Option<String> to) {
// …
}
Route:
GET /birthday controllers.Application.birthday(from: play.libs.F.Option[String], to: play.libs.F.Option[String])
You can also just pick arbitrary query parameters out as strings (you have to do the type conversion yourself):
public static Result birthdays(Option<String> from, Option<String> to) {
String blarg = request().getQueryString("blarg"); // null if not in URL
// …
}
For optional Query parameters, you can do it this way
In routes file, declare API
GET /birthdays controllers.Application.method(from: Long, to: Long)
You can also give some default value, in case API doesn't contain these query params it will automatically assign the default values to these params
GET /birthdays controllers.Application.method(from: Long ?= 0, to: Long ?= 10)
In method written inside controller Application these params will have value null if no default values assigned else default values.
My way of doing this involves using a custom QueryStringBindable. This way I express parameters in routes as:
GET /birthdays/ controllers.Birthdays.getBirthdays(period: util.Period)
The code for Period looks like this.
public class Period implements QueryStringBindable<Period> {
public static final String PATTERN = "dd.MM.yyyy";
public Date start;
public Date end;
#Override
public F.Option<Period> bind(String key, Map<String, String[]> data) {
SimpleDateFormat sdf = new SimpleDateFormat(PATTERN);
try {
start = data.containsKey("startDate")?sdf.parse(data.get("startDate") [0]):null;
end = data.containsKey("endDate")?sdf.parse(data.get("endDate")[0]):null;
} catch (ParseException ignored) {
return F.Option.None();
}
return F.Option.Some(this);
}
#Override
public String unbind(String key) {
SimpleDateFormat sdf = new SimpleDateFormat(PATTERN);
return "startDate=" + sdf.format(start) + "&" + "endDate=" + sdf.format(end);
}
#Override
public String javascriptUnbind() {
return null;
}
public void applyDateFilter(ExpressionList el) {
if (this.start != null)
el.ge("eventDate", this.start);
if (this.end != null)
el.le("eventDate", new DateTime(this.end.getTime()).plusDays(1).toDate());
}
}
applyDateFilter is just a convienence method i use in my controllers if I want to apply date filtering to the query. Obviously you could use other date defaults here, or use some other default than null for start and end date in the bind method.

Is there a way to capitalize the first letter of a value of a variable in Eclipse (Helios) code templates

I have a code template with a variable and I would like to capitalize(just the first letter) the value of this variable only in some occurrences. Is there a way to do this?
The template code is as follows - I would like to capitalize Property Name in my function names...
private $$${PropertyName};
${cursor}
public function get${PropertyName}()
{
return $$this->${PropertyName};
}
public function set${PropertyName}($$value)
{
$$this->${PropertyName} = $$value;
}
Please Note: This is a template for use with code templates in the IDE (not in PHP). For details see: http://www.ibm.com/developerworks/opensource/tutorials/os-eclipse-code-templates/index.html
I also want this and tried to build a custom TemplateVariableResolver to do it. (I already have one custom resolver in place that generates new UUIDs a la http://dev.eclipse.org/blogs/jdtui/2007/12/04/text-templates-2/.)
I made a custom resolver bound to capitalize:
public class CapitalizingVariableResolver extends TemplateVariableResolver {
#Override
public void resolve(TemplateVariable variable, TemplateContext context) {
#SuppressWarnings("unchecked")
final List<String> params = variable.getVariableType().getParams();
if (params.isEmpty())
return;
final String currentValue = context.getVariable(params.get(0));
if (currentValue == null || currentValue.length() == 0)
return;
variable.setValue(currentValue.substring(0, 1).toUpperCase() + currentValue.substring(1));
}
}
(plugin.xml:)
<extension point="org.eclipse.ui.editors.templates">
<resolver
class="com.foo.CapitalizingVariableResolver"
contextTypeId="java"
description="Resolves to the value of the variable named by the first argument, but with its first letter capitalized."
name="capitalized"
type="capitalize">
</resolver>
</extension>
that I would use like this: (I am working in Java; I see that you do not appear to be)
public PropertyAccessor<${propertyType}> ${property:field}() {
return ${property};
}
public ${propertyType} get${capitalizedProperty:capitalize(property)}() {
return ${property}.get();
}
public void set${capitalizedProperty}(${propertyType} ${property}) {
this.${property}.set(${property});
}
As of Eclipse 3.5, the problem I am having is that my custom resolver does not get a chance to re-resolve once I've specified a value for the property variable. It appears that the Java Development Tools (Eclipse JDT) do this dependent template variable re-resolution via a mechanism called MultiVariableGuess within the JavaContext (see addDependency()). Unfortunately for us, that mechanism does not seem to be exposed, so I/we can't use it to do the same (without lots of copy-and-paste or other redundant work).
At this point, I am giving up again for a while and will keep typing the leading-lowercase and leading-uppercase names separately into two independent template variables.