How to receive Map parameters in Resteasy? - resteasy

I would like to receive these HTTP parameters (POST) in my Resteasy service:
customFields[my_key]=some_value
customFields[my_key2]=some_value2
Something like this doesn't work:
#Form(prefix="customFields")
Map<String, String> customFields
... what happens here is that on the server the new Map is initialized, and the key for the Map entry is set (i.e. "my_key") but value is not set.
Does anyone know how to handle the case like mine, where I need to receive unknown number of fields (within a Map), but each of them properly structured (HTTP map/dictionary notation).

This is a known bug. The workaround is to use your own string wrapper as the map value type. For example:
public class StringWrapper implements Serializable {
private static final long serialVersionUID = 1L;
#FormParam("value")
public String value;
}
Redefine your map as:
#Form(prefix="customFields")
Map<String, StringWrapper> customFields;
And then pass the values to it as customFields[my_key].value=some_value

Related

CodenameOne: PropertyIndex.toJSON() not generating correct JSON for Lists of Objects

I have a mobile app where a user fills out a form, say an Event, and when they save I want to submit the data as JSON to the server. CN1 has the feature to generate JSON easily using PropertyBusinessObject so my Event is defined as follows:
public class Event implements PropertyBusinessObject {
public final Property<Long, Event> eventId = new Property<>("eventId");
public final Property<EventLocation, Event> eventLocation = new Property<>("eventLocation", EventLocation.class);
public final Property<List<EventItinerary>, Event> eventItineraryList = new Property<>("eventItineraryList", XXX);
private final PropertyIndex idx...
}
Both EventLocation and EventItinerary implement PropertyBusinessObject and I've found that when I generate the JSON for Event, EventLocation generates fine but not EventItinerary. When I try and use EventItinerary.class in the "XXX" section above, I get the following error...
Exception: java.lang.ClassCastException - class java.util.ArrayList cannot be cast to class com.codename1.properties.PropertyBusinessObject
which occurs at line 484 of com.codename1.properties.PropertyIndex.toMapRepresentationImpl()
When I use List.class for "XXX" or nothing i.e. new Property<>("eventItineraryList"); then it posts to the server but the JSON contains the name of the class and its memory address i.e.
{
"eventId": 3425567,
"eventLocation" : {
...
},
"eventItineraryList": [
"com.myapp.event.EventItinerary#cdc543c",
"com.myapp.event.EventItinerary#39987ocb",
"com.myapp.event.EventItinerary#cd5t776c",
]
}
My question is what should I put in "XXX" to have the EventItinerary objects have the correct JSON representation?
You need to use a ListProperty so we can traverse into it and the ListProperty should refer to a different PropertyBusinessObject. So this should look roughly like this:
public final ListProperty<EventItinerary, Event> eventItineraryList = new ListProperty<>("eventItineraryList", EventItinerary.class);
Notice the EventItinerary.class which is important. The generic valuegets lost due to erasure. The argument lets us reconstruct the object with the right object types when loading from JSON.'
Also again, for this to work EventItinerary must be a PropertyBusinessObject too.

Save result from Objectify in human readable form in datastore

I am trying to create an Eventlog (ORMSLOG in example), that saves events in human readable form in Datastore.
Doing this should write readable event:
List<Device> devices = ofy().transactionless().load().type(Device.class).list();
ORMSLOG.log(ORMSLOG.GET_ALL_DEVICES, "Devices found: " + String.valueOf(devices));
The ORMSLOG is a simple class.
public class ORMSLOG {
public final static String CREATE_DEVICE = "Create Device";
public final static String GET_ALL_DEVICES = "Get all Devices";
public static void log(final String event, final String data) {
ofy().save().entity(new Event(event, data)).now();
}
}
But the data saved in Datastore is not readable and looks like this:
ORMSLOG data
I need to transform the reference to the object into human readable text.
You are just logging the String representation of the objects, which is done by calling the toString method. Since you did not override the toString method in the Device class, you are getting the pointer to the objects. If you override the toString method in your Device class to return whatever state you want to return, you would see a much better result. Most IDEs (e.g. Eclipse) have an option to generate toString method for you.

How to use dynamic schema in spring data with mongodb?

Mongodb is a no-schema document database, but in spring data, it's necessary to define entity class and repository class, like following:
Entity class:
#Document(collection = "users")
public class User implements UserDetails {
#Id private String userId;
#NotNull #Indexed(unique = true) private String username;
#NotNull private String password;
#NotNull private String name;
#NotNull private String email;
}
Repository class:
public interface UserRepository extends MongoRepository<User, String> {
User findByUsername(String username);
}
Is there anyway to use map not class in spring data mongodb so that the server can accept any dynamic JSON data then store it in BSON without any pre-class define?
First, a few insightful links about schemaless data:
what does “schemaless” even mean anyway?
“schemaless” doesn't mean “schemafree”
Second... one may wonder if Spring, or Java, is the right solution for your problem - why not a more dynamic tool, such a Ruby, Python or the Mongoshell?
That being said, let's focus on the technical issue.
If your goal is only to store random data, you could basically just define your own controller and use the MongoDB Java Driver directly.
If you really insist on having no predefined schema for your domain object class, use this:
#Document(collection = "users")
public class User implements UserDetails {
#Id
private String id;
private Map<String, Object> schemalessData;
// getters/setters omitted
}
Basically it gives you a container in which you can put whatever you want, but watch out for serialization/deserialization issues (this may become tricky if you had ObjectIds and DBRefs in your nested document). Also, updating data may become nasty if your data hierarchy becomes too complex.
Still, at some point, you'll realize your data indeed has a schema that can be pinpointed and put into well-defined POJOs.
Update
A late update since people still happen to read this post in 2020: the Jackson annotations JsonAnyGetter and JsonAnySetter let you hide the root of the schemaless-data container so your unknown fields can be sent as top-level fields in your payload. They will still be stored nested in your MongoDB document, but will appear as top-level fields when the ressource is requested through Spring.
#Document(collection = "users")
public class User implements UserDetails {
#Id
private String id;
// add all other expected fields (getters/setters omitted)
private String foo;
private String bar;
// a container for all unexpected fields
private Map<String, Object> schemalessData;
#JsonAnySetter
public void add(String key, Object value) {
if (null == schemalessData) {
schemalessData = new HashMap<>();
}
schemalessData.put(key, value);
}
#JsonAnyGetter
public Map<String, Object> get() {
return schemalessData;
}
// getters/setters omitted
}

How to know what class is being deserialized in JackSon Deserializer?

I'm using app engine datastore so I have entity like this.
#PersistenceCapable
public class Author {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
#JsonProperty("id")
#JsonSerialize(using = JsonKeySerializer.class)
#JsonDeserialize(using = JsonKeyDeserializer.class)
private Key key;
....
}
When the model is sent to view, it will serialize the Key object as an Id value. Then, if I send data back from view I want to deserialize the Id back to Key object by using JsonKeyDeserializer class.
public class JsonKeyDeserializer extends JsonDeserializer<Key> {
#Override
public Key deserialize(JsonParser jsonParser, DeserializationContext deserializeContext)
throws IOException, JsonProcessingException {
String id = jsonParser.getText();
if (id.isEmpty()) {
return null;
}
// Here is the problem because I have several entities and I can't fix the Author class in this deserializer like this.
// I want to know what class is being deserialized at runtime.
// return KeyFactory.createKey(Author.class.getSimpleName(), Integer.parseInt(id))
}
}
I tried to debug the value in deserialize's parameters but I can't find the way to get the target deserialized class. How can I solve this?
You may have misunderstood the role of KeySerializer/KeyDeserializer: they are used for Java Map keys, and not as generic identifiers in database sense of term "key".
So you probably would need to use regular JsonSerializer/JsonDeserializer instead.
As to type: it is assumed that handlers are constructed for specific types, and no extra type information is passed during serialization or deserialization process: expected type (if handlers are used for different types) must be passed during construction.
When registering general serializers or deserializers, you can do this when implementing Module, as one of the arguments is type for which (de)serializer is requested.
When defining handlers directly for properties (like when using annotations), this information is available on createContextual() callback of interface ContextualSerializer (and -Deserializer), if your handler implements it: BeanProperty is passed to specify property (in this case field with annotation), and you can access its type. This information needs to be stored to be used during (de)serialization.
EDIT: as author pointed out, I actually misread the question: KeySerializer is the class name, not annotation.

GWT JsArray of self, recursive object array

I am building a tree structure which an object references itself in like so:
public class ProjectObjectOL extends JavaScriptObject {
protected ProjectObjectOL() { }
public final native boolean getStatus() /*-{ return this.status; }-*/;
public final native String getError() /*-{ return this.error_message; }-*/;
public final native JsArray<ProjectObjectOL> getChildren() /*-{ this.children; }-*/;
}
My problem is that I can't seem to get the children of the object. I've tested it out, and I'm quite sure the JSON structure being passed back consists of an object that contains an array of children of that type which can contain children, etc.
...but when trying to access even the simplest information about the children, the length of the array, it returns 0 every time. I've tried with no success to figure out what it's doing wrong, all the other data returns fine, but this one piece will NOT retrieve the children. Here is an example of how I might (directly) access the length for testing:
JSONObject oResults = (JSONObject) JSONParser.parse(response.getText());
ProjectListOL testoutputOL = oResults.isObject().getJavaScriptObject().cast();
ProjectObjectOL testObject = testoutputOL.getProjectList().get(1);
Window.alert(testObject.getChildren().length()+"");
A ProjectListOL contains an array of ProjectObjectOLs. In the example above I simply grabbed the one I KNOW has children. I'm using ColdFusion for the backend that returns the JSON object. Once again, I have output this object multiple times, both in GWT and outside (directly dumping the JSON object from the file) verifying that the object is indeed set up how I expect it to be set up.
I missed an obvious mistake:
public final native JsArray<ProjectObjectOL> getChildren() /*-{ this.children; }-*/;
OOPS:
public final native JsArray<ProjectObjectOL> getChildren() /*-{ **return** this.children; }-*/;

Resources