I want to save an array of Mission.class which have variables as follows:
public class Mission {
public MissionEnum missionEnum;
public int progress;
public Mission(MissionEnum missionEnum, int progress) {
this.missionEnum = missionEnum;
this.progress = progress;
}
and also save missions in another java class:
public void saveMissions() {
Json json = new Json();
json.setOutputType(JsonWriter.OutputType.json);
json.addClassTag("Mission", Mission.class);
FileHandle missionFile = Gdx.files.local("missions_array.json");
missionFile.writeString(json.prettyPrint(missions), false);
}
and load missions:
public void loadMissions() {
if (Gdx.files.local("missions_array.json").exists()) {
try {
FileHandle file = Gdx.files.local("missions_array.json");
Json json = new Json();
json.addClassTag("Mission", Mission.class);
missions = json.fromJson(Array.class, Mission.class, file);
for (Mission mission : missions) {
Gdx.app.log(TAG, "Mission loaded: " + mission.missionEnum);
}
Gdx.app.log(TAG, "Load missions successful");
} catch (Exception e) {
Gdx.app.error(TAG, "Unable to read Missions: " + e.getMessage());
}
}
}
I got json like this:
[
{
"class": "Mission",
"missionEnum": "BUY_POWERUP"
},
{
"class": "Mission",
"missionEnum": "DISTANCE_ONE_RUN_2"
},
{
"class": "Mission",
"missionEnum": "BANANA_TOTAL_2",
"progress": 35
}
]
However when loadMissions() is run I got the "Load missions successful" log shown but "Mission loaded..." aren't shown without any error log. Missions appeared not loaded properly. I do not know what went wrong because another array is loaded successful the same way.
Not sure why there are no errors in the logs, since while reproducing your problem I've got an exception.
The problem is in loadMissions() method: you create new Json parser without setting the class tag:
Json json = new Json();
// add the line below
json.addClassTag("Mission", Mission.class);
missions = json.fromJson(Array.class, Mission.class, file);
....
Without the tag parser doesn't know what is "class": "Mission" in json file.
Update
Another thing that may cause this issue is the args-constructor. At least, when I added it I got an exception. If you don't use it - just delete.
Still, quite weird that you don't have any exceptions in logs'cos I definitely have.
Updated response:
Add an empty contructor and read this and this
You will either have to add a no-argument constructor to (Mission), or
you will have to add a custom serializer (see
https://code.google.com/p/libgdx/wiki/JsonParsing#Customizing_serialization)
that knows how to save a (Mission) instance and knows the appropriate
constructor to invoke when reading a (Mission) back in.
public Mission() {
// Do nothing.
}
Reading & writing JSON
The class implementing Json.Serializable must have a zero argument
constructor because object construction is done for you.
Alternatively delete the unused constructor. I think Enigo answer is also correct so I'm going to upvote his answer.
Providing Constructors for Your Classes
You don't have to provide any constructors for your class, but you
must be careful when doing this. The compiler automatically provides a
no-argument, default constructor for any class without constructors.
This default constructor will call the no-argument constructor of the
superclass. In this situation, the compiler will complain if the
superclass doesn't have a no-argument constructor so you must verify
that it does. If your class has no explicit superclass, then it has an
implicit superclass of Object, which does have a no-argument
constructor.
Note: I didn't test our responses, I have not developed games or used libgdx in the last two years.
Also read this libgdx issue: Json - constructor default value with Enum:
I don't know if this would be called a bug but, I have a case where I
have an enum like this;
Then I have a class with 2 constructors;
This second gets called by my framework, the first by Json
deserialization.
...
Previous response:
I guess that the missing progress field in some Mission classes can be the source of the issue but would be interesting to read the error logs to be sure.
I followed this, this and this to confirm this but it's hard without extra information about the exact log error.
Related
I have a form that contains multiple radio inputs and one textarea input that I send using axios from a ReactJs client. The request looks like this:
axios.post("/wellbeing/" + params.wellbeingSurveyType, { formAnswersJson: formAnswers })
.then(res => {
// logic
})
.catch(err => {
// logic
})
The 'formAnswers' object looks like this:
I then receive the request from a Spring controller that looks like the following:
#PostMapping("{wellbeingSurveyType}")
public WellbeingSurveySubmission submitSurvey(
#PathVariable WellbeingSurveyType wellbeingSurveyType,
#RequestBody String formAnswersJson) throws JsonProcessingException {
var result = new ObjectMapper().readValue(formAnswersJson, HashMap.class);
return new WellbeingSurveySubmission(); //ignore this
}
When I call the 'toString()' method on the result object it seems to correctly print out the map values:
But when I try to actually operate on the object (which is parsed as a LinkedHashMap) I cannot access the keys or values:
When I try to open up the object using the debugging tool it seems to store a reference to itself as a value:
The result I want is simply a Map<String, String> that represents the JSON but I am unsure why this behavior is happening.
Any help or tips on how to do this in a better way would be greatly appreciated, thank you.
Alright the best way I found to make this work was to deconstruct the JSON object in the axios post request like so:
axios.post("/wellbeing/" + params.wellbeingSurveyType, { ...formAnswers })
.then(res => {
// logic
})
.catch(err => {
// logic
})
Works better as if I just pass the formAnswers object it unnecessarily wraps the object i.e. A hashmap that contains a single key-value pair 'formAnswers'.
Although as The Frozen One mentioned, it would be better to define a dedicated form object and take it as a param in the spring controller.
If you pass a JavaScript object as the 2nd parameter to the axios.post() function, Axios will automatically serialize the object to JSON for you.
So, with this line of code :
axios.post("/wellbeing/" + params.wellbeingSurveyType, { formAnswersJson: formAnswers })
You are basically sending object with key fromAnswersJson and value fromAnswers to your rest controller and Spring will deserilize it like a Map with key fromAnswersJson and value fromAnswers
To get what you want just send your request like this :
axios.post("/wellbeing/" + params.wellbeingSurveyType, formAnswers )
It Seems like the conversion from String to Map in java does not go smoothly from what I see in your printscreen.
Personally, I do not work like that when I handle requests. I create a dto object and give that in the controller as input. The fact that you have variables that the name is a number make that a bit more complicated since java cannot accept that as a valid variable name, but probably (did not test it) can be overcome by using #JsonProperty. So my solution would be the following
#Getter
#Setter
public class MyRequestDto {
#JsonProperty("user-comment")
private String userComment;
#JsonProperty("0")
private String zero;
#JsonProperty("1")
private String one;
#JsonProperty("2")
private String two;
...
}
I added lombok getters and setters ofcourse you can add your own if you don't use lombok.
Then replace the input in your controller
#PostMapping("{wellbeingSurveyType}")
public WellbeingSurveySubmission submitSurvey(
#PathVariable WellbeingSurveyType wellbeingSurveyType,
#RequestBody MyRequestDto request) throws JsonProcessingException {
request.getUserComment()
return new WellbeingSurveySubmission(); //ignore this
}
I need to dynamically assign values of cacheResolver for #Cacheable in runtime because cacheResolver has the same value for #Cacheable in every method. Hence, I use Spring AOP to dynamically assign the value but then Spring does not recognize the newly added value for cacheResolver.
Seems that AOP load #Cacheable value at the beginning.
Anyone knows how to make it work?
My AOP code:
#Aspect
#Component
#Order(1)
public class CacheableAspect {
#Pointcut("#annotation(org.springframework.cache.annotation.Cacheable)")
public void cacheablePointCut() {}
#Before("cacheablePointCut()")
public void addCacheableResolver(JoinPoint joinPoint) {
Annotation cacheableAnnotation = getCacheableAnnotation(joinPoint);
Object handler = Proxy.getInvocationHandler(cacheableAnnotation);
Field f;
try {
f = handler.getClass().getDeclaredField("memberValues");
} catch (NoSuchFieldException | SecurityException e) {
throw new IllegalStateException(e);
}
f.setAccessible(true);
Map<String, Object> memberValues;
try {
memberValues = (Map<String, Object>) f.get(handler);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
memberValues.put("cacheResolver", "cacheableResolver");
}
private Annotation getCacheableAnnotation(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
return method.getAnnotation(Cacheable.class);
}
}
My #Cacheable code in which i want cacheResolver is dynamically assigned a value:
#Cacheable(value = "test")
public int test() {
System.out.println("xxx");
return 10;
}
OK, so you are trying to dynamically change an annotation representation in the JVM during runtime. Not only is that ugly, but it probably does not work as you hope it would. It seems you found out that specific annotations are represented by a dynamic proxy instance during runtime, then you are successfully manipulating one of its field values. But annotations are meant to be immutable, aber depending on when e.g. Spring scans the annotations while wiring the application, your approach to modify the proxy fields later, while being a nice try, just comes too late.
How about a more canonical approach to use multiple cache managers and/or a resolver which dynamically does what you need to begin with? As much as I love AOP, it is not the answer to everyhing.
By the way, even though your aspect is kind of useless in this case, at least we can use it as an example of how to bind annotation values to advice methods parameters, i.e. you do not need to fetch the annotation from the method by reflection next time you write an aspect:
#Pointcut("#annotation(cacheable)")
public void cacheablePointCut(Cacheable cacheable) {}
#Before("cacheablePointCut(cacheable)")
public void addCacheableResolver(JoinPoint joinPoint, Cacheable cacheable) {
Object handler = Proxy.getInvocationHandler(cacheable);
// (...)
}
Both Java and Javascript allow for a different way of executing static code. Java allows you to have static code in the body of a class while JS allows you to execute static code outside class definitions. Examples:
Java:
public class MyClass {
private static Map<String,String> someMap = new HashMap<String,String();
static {
someMap.put("key1","value");
someMap.put("key2","value");
SomeOtherClass.someOtherStaticMethod();
System.out.println(someMap);
}
}
JS (basically any JS code outside a class):
var myint = 5;
callSomeMethod();
$(document).ready(function () {
$("#hiddenelement").hide();
});
However, it seems like Dart supports either of both ways. Declaring global variables and methods is supported, but calling methods and executing code like in JS is not. This can only be done in a main() method. Also, static code inside a class is not allowed either.
I know Dart has other ways to statically fill a Map like my first example, but there is another case that I can think of for which this is required.
Let's consider the following CarRegistry implementation that allows you to map strings of the car model to an instance of the corresponding class. F.e. when you get the car models from JSON data:
class CarRegistry {
static Map<String, Function> _factoryMethods = new HashMap<String, Function>();
static void registerFactory(String key, Car factory()) {
_factoryMethods[key] = factory;
}
static Car createInstance(String key) {
Function factory = _factoryMethods[key];
if(factory != null) {
return factory();
}
throw new Exception("Key not found: $key");
}
}
class TeslaModelS extends Car {
}
class TeslaModelX extends Car {
}
In order to be able to call CarRegistry.createInstance("teslamodelx");, the class must first be registered. In Java this could be done by adding the following line to each Car class: static { CarRegistry.registerFactory("teslamodelx" , () => new TeslaModelX()); }. What you don't want is to hard-code all cars into the registry, because it will lose it's function as a registry, and it increases coupling. You want to be able to add a new car by only adding one new file. In JS you could call the CarRegistry.registerFactory("teslamodelx" , () => new TeslaModelX()); line outside the class construct.
How could a similar thing be done in Dart?
Even if you would allow to edit multiple files to add a new car, it would not be possible if you are writing a library without a main() method. The only option then is to fill the map on the first call of the Registry.createInstance() method, but it's no longer a registry then, just a class containing a hard-coded list of cars.
EDIT: A small addition to the last statement I made here: filling this kind of registry in the createInstance() method is only an option if the registry resided in my own library. If, f.e. I want to register my own classes to a registry provided by a different library that I imported, that's no longer an option.
Why all the fuss about static?
You can create a getter that checks if the initialization was already done (_factoryMethods != null) if not do it and return the map.
As far a I understand it, this is all about at what time this code should be executed.
The approach I showed above is lazy initialization.
I think this is usually the preferred way I guess.
If you want to do initialization when the library is loaded
I don't know another way as calling an init() method of the library from main() and add initialization code this libraries init() method.
Here is a discussion about this topic executing code at library initialization time
I encountered the same issue when trying to drive a similarly themed library.
My initial attempt explored using dart:mirrors to iterate over classes in a library and determine if they were tagged by an annotation like this (using your own code as part of the example):
#car('telsamodelx')
class TelsaModelX extends Car {
}
If so, they got automatically populated into the registry. Performance wasn't great, though, and I wasn't sure if how it was going to scale.
I ended up taking a more cumbersome approach:
// Inside of CarRegistry.dart
class CarRegister {
static bool _registeredAll = false;
static Car create() {
if (!_registeredAll) { _registerAll()); }
/* ... */
}
}
// Inside of the same library, telsa_model_x.dart
class TelsaModelX extends Car {}
// Inside of the same library, global namespace:
// This method registers all "default" vehicles in the vehicle registery.
_registerAll() {
register('telsamodelx', () => new TelsaModelX());
}
// Inside of the same library, global namespace:
register(carName, carFxn) { /* ... */ }
Outside of the library, consumers had to call register(); somewhere to register their vehicle.
It is unnecessary duplication, and unfortunately separates the registration from the class in a way that makes it hard to track, but it's either cumbersome code or a performance hit by using dart:mirrors.
YMMV, but as the number of register-able items grow, I'm starting to look towards the dart:mirrors approach again.
I'm trying to implement a somewhat general converter, which transforms the data based on a given annotation. Say I want to transform these annotated strings in any matter.
All is well, until the code hits my converter's "matches" method. The "sourceType" I'm getting is always stripped out of all of the useful information. Has anyone had any success with such a setup, or am I missing something?
public class TestStringWriteConverter implements ConditionalGenericConverter {
#Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
if (sourceType.hasAnnotation(GivenAnnotation.class)) {
//->never gets executed, because sourceType is being stripped out of it's useful infos
}
I followed the problem to MappingMongoConverter from this package org.springframework.data.mongodb.core.convert
protected void writeInternal(Object obj, final DBObject dbo, MongoPersistentEntity<?> entity) {
//...
if (null != propertyObj) {
if (!conversions.isSimpleType(propertyObj.getClass())) {
writePropertyInternal(propertyObj, dbo, prop);
} else {
// I always end up here, which is correct but the whole prop object is being omitted in favor of the getFieldName() property
writeSimpleInternal(propertyObj, dbo, prop.getFieldName());
}
}
}
The spring versions I'm using:
<spring.version>3.2.5.RELEASE</spring.version>
<spring.data.version>1.3.2.RELEASE</spring.data.version>
Any help is much appreciated.
I think you misunderstand what sourceType.hasAnnotation(…) actually returns. As the name suggests, it inspects the type for annotations. So for a given type like this:
#MyAnnotation
class Foo { }
it would allow you to find #MyAnnotation. However you are writing about "annotated strings". I assume you mean something like:
class Bar {
#MyAnnotation
String property;
}
This is not a type annotation and the Converter API is not meant to cover such cases. If you think supporting such scenarios would be worthfile, please file a JIRA ticket.
I'm looking at using oData endpoints in my Silverlight client. Naturally, I'm doing MVVM and I want the project to be nice and "Blendable" (i.e. I must be able to cleanly use static data instead of the oData endpoints when in design mode.)
Now to the problem. I'd like to use the DataServiceCollection in my ViewModels, since it allows for nice bindable collections without having to worry too much with BeginExecute/EndExecute etc.
Now, let's look at some code. My Model interface looks like this:
public interface ITasksModel
{
IQueryable<Task> Tasks { get; }
}
The oData endpoint implementation of that interface:
public class TasksModel : ITasksModel
{
Uri svcUri = new Uri("http://localhost:2404/Services/TasksDataService.svc");
TaskModelContainer _container;
public TasksModel()
{
_container = new TaskModelContainer(svcUri);
}
public IQueryable<Task> Tasks
{
get
{
return _container.TaskSet;
}
}
}
And the "Blendable" design-time implementation:
public class DesignModeTasksModel : ITasksModel
{
private List<Task> _taskCollection = new List<Task>();
public DesignModeTasksModel()
{
_taskCollection.Add(new Task() { Id = 1, Title = "Task 1" });
_taskCollection.Add(new Task() { Id = 2, Title = "Task 2" });
_taskCollection.Add(new Task() { Id = 3, Title = "Task 3" });
}
public IQueryable<Task> Tasks
{
get {
return _taskCollection.AsQueryable();
}
}
}
However, when I try to use this last one in my ViewModel constructor:
public TaskListViewModel(ITasksModel tasksModel)
{
_tasksModel = tasksModel;
_tasks = new DataServiceCollection<Task>();
_tasks.LoadAsync(_tasksModel.Tasks);
}
I get an exception:
Only a typed DataServiceQuery object can be supplied when calling the LoadAsync method on DataServiceCollection.
First of all, if this is the case, why not make the input parameter of LoadAsync be typed as DataServiceQuery?
Second, what is the "proper" way of doing what I'm trying to accomplish?
The reason LoadAsync requires DataServiceQuery is that just plain IQueryable doesn't define asynchronous way of executing the query. The reason the method takes IQueryable type as its parameter is so that users don't have to cast the query object to DataServiceQuery explicitely (makes the code shorter) and since we assume that users will try to run their code at least once, they would see the error immediately (as you did).
LoadAsync only supports asynchronous operations, so it needs the DataServiceQuery. If you already have the results (without a need to execute async request) you can call the Load method instead. Which is the answer to your second question. Instead of calling LoadAsync for both desing time and run time, you could use Load for design time and LoadAsync for run time. But due to tracking constrains you might need to create the DataServiceCollection in different way.
Something like this:
DataServiceCollection<Task> dsc;
DataServiceQuery<Task> dsq = _tasksModel as DataServiceQuery<Task>;
if (dsq != null)
{
dsc = new DataServiceCollection<Task>();
dsc.LoadAsync(dsq);
}
else
{
dsc = new DataServiceCollection<Task>(myDataServiceContext);
dsc.Load(_tasksModel);
// Invoke the LoadAsyncCompleted handler here
}
If you pass the DataServiceContext to the constructor before caling Load the entities will be tracked (just like in the LoadAsync case). If you don't need that you can call the constructor which takes IEnumerable and TrackingMode and turn off tracking on it.