I tried with active annotation of xtend, and I want to create a live annotation which can generate a String[] field to record the names of method parameters.
#Target(ElementType::TYPE)
#Active(typeof(ParameterRecorderProcessor))
annotation ParameterRecorder {
}
class ParameterRecorderProcessor extends AbstractClassProcessor {
override doTransform(MutableClassDeclaration annotatedClass, extension TransformationContext context) {
var iii = 0;
// add the public methods to the interface
for (method : annotatedClass.declaredMethods) {
if (method.visibility == Visibility::PUBLIC) {
iii = iii + 1
annotatedClass.addField(method.simpleName + "_" + iii) [
type = typeof(String[]).newTypeReference // String[] doesn't work
var s = ""
for (p : method.parameters) {
if(s.length > 0) s = s + ","
s = s + "\"" + p.simpleName + "\""
}
val ss = s
initializer = [
'''[«ss»]'''
]
]
}
}
}
}
You can see I use typeof(String[]).newTypeReference to define the type of new created field, but it doesn't work. The generated java code is looking like:
private Object index_1;
It uses Object and the initializer part has be empty.
How to fix it?
This looks like a bug to me. As a workaround, you may want to use typeof(String).newTypeReference.newArrayTypeReference or more concise string.newArrayTypeReference
Related
How can I turn a JSON object, i.e. { username: "john", password: "1234" } into an OData string query in a function using typescript? I could not find a library to do this for me (Angular 6). Here is my attempt:
function ConvertToODataString (json: Object) {
let ret_str: string = "";
for (let key in json) {
ret_str += (key + "=" + json[key] + "&");
}
if (ret_str) {
ret_str = ret_str.substr(0, ret_str.length - 1); // remove last &
}
return ret_str;
}
Does anyone know of a better way? For now, my json is not multi-leveled.
You can use for ... in to enumerate the object properties, adding each key/value pair to an array, and combine the values with Array.join:
function convertObjectToQuery(obj: Object): string {
let values = new Array<string>();
for (let prop in obj) {
values.push(`${prop} eq '${obj[prop]}'`);
}
return encodeURI("$filter=" + values.join(" and "));
}
See this stackblitz for a demo.
JSON.parse function.
Example:
var obj = JSON.parse('{ "name":"John", "age":30, "city":"New York"}');
json={ "name":"John", "age":30, "city":"New York"};
var obj = JSON.parse(json+'');
I decided to use the HttpParms module instead:
import { HttpParams } from "#angular/common/http";
const params = new HttpParams()
.set("$filter", "Username eq '" + parameters["Username"] + "' and Password eq '" + parameters["Password"] + "'")
.set("$count", "true");
console.log(params.toString());
Maybe somebody knows about the best way to implement data binding in CreateJS? E.g. when changes of properties in ClassA call some listener-functions in ClassB ?
In Flash(Flex) it's possible to use some meta-tags to tell compiler which properties should be used as bindable. After that, during compilation compiler makes some changes in the code (e.g. wraps the required properties into get/set methods, and in the set methods there are dispatching events functionality).
Do we have something similar in CreateJS?
How it works in AS3 (a very simple example):
public class ClassA
{
[Bindable]
public var bindableProperty:String;
}
public class ClassB
{
protected var classA:ClassA;
public function GameModel()
{
this.classA = new ClassA();
BindingUtils.bindSetter(this.bindingCallback, this.classA, "bindableProperty");
}
public function bindingCallback()
{
// Do something after binding callback
}
}
There's no near equivalent to the [Bindable] Flex meta-tag in JavaScript or CreateJS.
In the future, Object.observe() could be a close equivalent to Flex's bindSetter.
For now you can use getter/setter properties to invoke callbacks when properties are changed. Here's a simple example:
function bindSetter(host, property, callback) {
if(!host[property + "_bindings"]){
host[property + "_bindings"] = [];
host["_" + property] = host[property];
Object.defineProperty(host, property, {
get: function() {
return host["_" + property];
},
set: function(newValue) {
host["_" + property] = newValue;
host[property + "_bindings"].forEach(function(callback){
callback(newValue);
});
}
});
}
host[property + "_bindings"].push(callback);
}
Now you can use bindSetter in a similar way to Flex:
var user = { name: "Aaron" }
bindSetter(user, "name", function(newValue){
log("Callback: " + newValue);
});
bindSetter(user, "name", function(newValue){
log("Another callback: " + newValue);
});
log("Initial value: " + user.name);
user.name = "Joe";
Should output:
Initial value: Aaron
Callback: Joe
Another callback: Joe
Binding to DOM element values is another problem, though, as they do not behave the same as regular JavaScript objects. Of course, there are many JS frameworks out there to accomplish data-binding with DOM elements, like Angular, Backbone, Knockout, etc. Mileage will vary when trying to mix other frameworks with CreateJS, though.
Update:
An equivalent unbindSetter could be done as follows:
function unbindSetter(host, property, callback){
var bindings = host[property + "_bindings"];
if(bindings){
var index = bindings.indexOf(callback);
if(index > -1){
bindings.splice(index, 1);
}
}
}
Now you can remove a callback that was previously added:
var user = { name: "Aaron" }
bindSetter(user, "name", myCallback);
function myCallback(newValue){
alert("Callback: " + newValue);
}
user.name = "Joe"; // alerts "Callback: Joe"
unbindSetter(user, "name", myCallback);
user.name = "Bob"; // no alert
I'm a little stumped why I can't pull the "Type" field out of my JSON stream to make a decision. It seems like this should be so easy.
I have the following JSON that I have as input:
[
{
"Institution":"ABC",
"Facility":"XYZ",
"Make":"Sunrise",
"Model":"Admission",
"SerialNumber":"",
"Revision":"1",
"Type":"ABC_Admission",
"ArchiveData":"<CSV file contents>"
}
]
In my Java I have a try-catch block with a JsonHolder class that implements Serializable to hold the JSON. Here's the Java I currently have:
try {
// Parse and split the input
JsonHolder data = JsonHolder.getField("text", input);
DataExtractor.LOG.info("JsonHolder data= " + data);
TreeNode node = data.getTreeNode();
DataExtractor.LOG.info("node size= " + node.size());
node = node.path("Type");
JsonNode json = (JsonNode) node;
DataExtractor.LOG.info("json= " + json.asText());
// code to decide what to do based on Type found
if (json.asText().equals("ABC_Admission")) {
// do one thing
} else {
// do something else
}
} catch (IOException iox) {
DataExtractor.LOG.error("Error extracting data", iox);
this.collector.fail(input);
}
When I run my code I get the following output (NOTE: I changed my package name where the class is to just for this output display)
25741 [Thread-91-DataExtractor] INFO <proprietary package name>.DataExtractor - JsonHolder data= [
{
"Institution":"ABC",
"Facility":"XYZ",
"Make":"Sunrise",
"Model":"Admission",
"SerialNumber":"",
"Revision":"1",
"Type":"ABC_Admission",
"ArchiveData":"<CSV file contents>"
}
]
25741 [Thread-91-DataExtractor] INFO <proprietary package name>.DataExtractor - node size= 1
25741 [Thread-91-DataExtractor] INFO <proprietary package name>.DataExtractor - json=
As you can see I don't get anything out. I just want to extract the value of the field "Type", so I was expecting to get the value "ABC_Admission" in this case. I would have thought the node path would separate out just that field from the rest of the JSON tree.
What am I doing wrong?
After consulting with another developer I found out the issue is my JSON is inside an array. So, I need to iterate over that array and then pull out the Type field from the object.
The updated code to resolve this is below:
try {
// Parse and split the input
JsonHolder data = JsonHolder.getField("text", input);
DataExtractor.LOG.info("JsonHolder data= " + data);
TreeNode node = data.getTreeNode();
String type = null;
// if this is an array of objects, iterate through the array
// to get the object, and reference the field we want
if (node.isArray()){
ArrayNode ary = (ArrayNode) node;
for (int i = 0; i < ary.size(); ++i) {
JsonNode obj = ary.get(i);
if (obj.has("Type")) {
type = obj.path("Type").asText();
break;
}
}
}
if (type == null) {
// Do something with failure??
}
DataExtractor.LOG.info("json= " + type);
if (type.equals("ABC_Admission")) {
// do one thing
else {
// do something else
}
} catch (IOException iox) {
DataExtractor.LOG.error("Error extracting data", iox);
this.collector.fail(input);
}
With reference to this,
How do I change the contents of a ListView in Scala?
I could change ListView contents by changing listData. However, I couldn't get ListView to publish these events, ListElementsAdded, ListElementsAdded and ListChanged. From the looks of ListView source, it would only adds a listener to a read-only empty model. How do I go about this?
Thanks
Later on, I managed to figure out a way to have ListView published these events., please refer to the code.
Is the right to go about it? Is there a better way to do this? Please advise.
Thanks
** code borrowed and modified **
object ListViewTest extends SimpleSwingApplication
{
lazy val top = new MainFrame
{
title = "ListView Test"
contents = new BoxPanel(Orientation.Vertical)
{
border = Swing.EmptyBorder(2, 2, 2, 2)
val listModel = new DefaultListModel
List("First", "Second", "Third", "Fourth", "Fifth").map(listModel.addElement(_))
val myList = ListBuffer()
val listView = new ListView[String](myList)
{
selection.intervalMode = ListView.IntervalMode.Single
peer.setModel(listModel)
//listData = myList
}
listView.peer.getModel.addListDataListener(new ListDataListener {
def contentsChanged(e: ListDataEvent) { publish(ListChanged(listView)) }
def intervalRemoved(e: ListDataEvent) { publish(ListElementsRemoved(listView, e.getIndex0 to e.getIndex1)) }
def intervalAdded(e: ListDataEvent) { publish(ListElementsAdded(listView, e.getIndex0 to e.getIndex1)) }
})
contents += new ScrollPane(listView)
val label = new Label("No selection")
contents += label
val b = new Button("Remove")
contents += b
listenTo(listView.selection, listView, b)
reactions +=
{
case ListSelectionChanged(list, range, live) =>
label.text = "Selection: " + range
case e: ButtonClicked =>
if (listView.listData.isEmpty)
{
b.enabled = false
}
else
{
listView.peer.getModel.asInstanceOf[DefaultListModel].remove(listView.selection.anchorIndex)
}
case ListElementsRemoved(source, range) =>
println("Element at " + (range.start + 1) + " is removed.")
}
}
pack
}
I'm using renderJSON(Object) to return some objects as JSON values, and it's working fine except for one field. Is there an easy way to add in that one field without having to manually create the whole json template?
Play uses GSON to build the JSON string. If your one field is a specific object type, then you can easily do this by providing a customised serialisation for that type. See the documentation here
http://sites.google.com/site/gson/gson-user-guide#TOC-Custom-Serialization-and-Deserializ
However, if it is an Integer class for example, that you want to work in one way for one, and another way for another, then you may have a little more difficulty.
Example
GsonBuilder gson = new GsonBuilder();
gson.registerTypeAdapter(SpecificClass.class, new MySerializer());
private class MySerializer implements JsonSerializer<DateTime> {
public JsonElement serialize(SpecificClass src, Type typeOfSrc, JsonSerializationContext context) {
String res = "special format of specificClass"
return new JsonPrimitive(res);
}
}
Simply do a
JsonElement elem = new Gson().toJsonTree(yourObject);
JsonObject obj = elem.getAsJsonObject();
obj.remove("xxx");
obj.addProperty("xxx", "what you want");
// other stuff ...
renderJSON(obj.toString());
etc.
After evaluating the play framework we hit a stumbling block and decision choice on serializing JSON for an external API. Allot of articles out there suggest using the Lift framework within play which just seem like extra overhead.After trying some of the frameworks / modules with in the play framework a college and myself decided to write a light weight code block that could cater for our needs.
case class User (
user_id: Int,
user_name: Option[String],
password: Option[String],
salt: Option[String]
) extends Serializable {
def toXml =
<user>
<user_id>{user_id}</user_id>
<user_name>{user_name.getOrElse("")}</user_name>
</user>
override def toJson =
"{" + JSON.key("user_id") + JSON.value(user_id) + ", " + JSON.key("user_name") + JSON.value(user_name) + "}"
}
class Serializable {
def toJson = ""
}
object JSON {
def key(x:String) = value(x) + ": "
def value(x:Any):String = {
x match {
case s:String => "\"" + s + "\""
case y:Some[String] => value(y.getOrElse(""))
case i:Int => value(i.toString)
case s:Serializable => s.toJson
case xs:List[Any] => "[" + xs.map(x => value(x)).reduceLeft(_ + ", " + _) + "]"
}
}
}
def searchUserByName(user_name: String) = {
(for (
u <- Users if u.user_name.like(("%"+user_name+"%").bind)
) yield u.*)
.list
.map(User.tupled(_))
}
def toXml(users:List[User]) = {
<users>
{ users.map(u => u.toXml) }
</users>
}
def toJson(users:List[User]) = {
"[" + users.map(u => u.toJson).reduceLeft(_ + ", " + _) + "]"
}
And from the controller.
// -- http://localhost:9000/api/users/getUser/xml
// -- http://localhost:9000/api/users/getUser/json
def getUser(requestType:String) = {
db withSession{
val user = Users.byUserName("King.Kong")
if(requestType == "xml") {
Xml(user.toXml)
} else {
user.toJson
}
}
}
//--- http://localhost:9000/api/users/searchuser/xml
//--- http://localhost:9000/api/users/searchuser/json
def searchUser(requestType:String) = {
db withSession{
val users = Users.searchUserByName("Doctor.Spoc")
if(requestType == "xml") {
Xml(Users.toXml(users))
} else {
val jsonList = Users.toJson(users)
Json(jsonList)
}
}