passing a function pointer to a method - function

I've read some posts about function pointers but I still don't understand how to use 'function pointers' the best for my case. Also in this case It isn't clear to me the use of anonymous classes...
Here the code:
class Fitness {
private List < Double > list;
interface Foo {
//public Foo;
Object myFunc(Object arg);
Object myFunc2(Object arg);
}
public Fitness(List < Double > list) {
this.list = new ArrayList < Double > (list);
}
public void bar(Foo foo) {
Object object = foo.myFunc(list);
System.out.println(object);
Object object2 = foo.myFunc2(list);
System.out.println(object2);
}
public void method(String func) {
if (func.equals("f1"))
bar(
new Foo() {
public Object myFunc(Object arg) {
return (Double)((List) arg).get(0) + 50.0;
}
public Object myFunc2(Object arg) {
return (Double)((List) arg).get(0) + 50.0;
}
});
else if (func.equals("f2"))
bar(
new Foo() {
public Object myFunc(Object arg) {
List < Double > l = (List < Double > ) arg;
return l.get(0) / l.size();
}
public Object myFunc2(Object arg) {
List < Double > l = (List < Double > ) arg;
return l.get(0) / l.size();
}
});
}
public void fitness1() {
bar(
new Foo() {
public Object myFunc(Object arg) {
return (Double)((List) arg).get(0) + 50.0 * 1000;
}
public Object myFunc2(Object arg) {
return (Double)((List) arg).get(0) + 50.0;
}
});
}
}
class Example {
public static void main(String[] args) {
ArrayList < Double > listD = new ArrayList < Double > ();
listD.add(100.0);
listD.add(-1.0);
listD.add(-5.0);
Fitness t = new Fitness(listD);
//t.method("f1");
//t.method("f2");
//t.method2();
t.fitness1();
}
}
What I would like is an object Fitness that call a fitness function according to some parameters. A fitness method should be able to take a list of int, double, even couple <int, String>.
I want to do a test: so I want to see the different results if I choose f1, f2, f3, f4. I am confused about how to code it.
Thanks in advance

You can declare the following interface:
interface FooFunc {
Object invoke(Foo foo, Object arg);
}
Then change slightly your bar() method:
public void bar(Foo foo, FooFunc func) {
Object object = func.invoke(foo, list);
System.out.println(object);
}
... and your fitness1() method:
public void fitness1(FooFunc func) {
bar(
new Foo() {
public Object myFunc(Object arg) {
return (Double) ((List) arg).get(0) + 50.0 * 1000;
}
public Object myFunc2(Object arg) {
return (Double) ((List) arg).get(0) + 50.0;
}
}, func);
}
Now, from your main() method, you can do:
Fitness t = new Fitness(listD);
t.fitness1(Fitness.Foo::myFunc);
t.fitness1(Fitness.Foo::myFunc2);
Isn't it great?
UPDATE: Complete file
import java.util.ArrayList;
import java.util.List;
class Fitness {
private List<Double> list;
interface Foo {
//public Foo;
Object myFunc(Object arg);
Object myFunc2(Object arg);
}
interface FooFunc {
Object invoke(Foo foo, Object arg);
}
public Fitness(List<Double> list) {
this.list = new ArrayList<Double>(list);
}
public void bar(Foo foo, FooFunc func) {
Object object = func.invoke(foo, list);
System.out.println(object);
}
public void fitness1(FooFunc func) {
bar(
new Foo() {
public Object myFunc(Object arg) {
return (Double) ((List) arg).get(0) + 50.0 * 1000;
}
public Object myFunc2(Object arg) {
return (Double) ((List) arg).get(0) + 50.0;
}
}, func);
}
}
public class Example {
public static void main(String[] args) {
ArrayList<Double> listD = new ArrayList<>();
listD.add(100.0);
listD.add(-1.0);
listD.add(-5.0);
Fitness t = new Fitness(listD);
t.fitness1(Fitness.Foo::myFunc);
t.fitness1(Fitness.Foo::myFunc2);
}
}

Related

Is there a way to ignore JsonSyntaxException in Gson

I have a json that looks like this:
[
{
_id: "54b8f62fa08c286b08449b8f",
loc: [
36.860983,
31.0567
]
},
{
_id: "54b8f6aea08c286b08449b93",
loc: {
coordinates: [ ]
}
}
]
As you can see, loc object is sometimes is a json object, sometimes is a double array. Without writing a custom deserializer, is there a way to avoid JsonSyntaxException and set the loc object to null when it is a json object rather than a double array.
There aren't any easy way (I mean a property/method call at Gson) for custom seralization/deserialization of a specific field at a json value.
You can see source code of com.google.gson.internal.bind.ReflectiveTypeAdapterFactory, and debug on its inner class Adapter's read method. (That's where your JsonSyntaxException occurs)
You can read Custom serialization for JUST specific fields and track its links. It may be implemented at future release of Gson. (Not available at latest release 2.2.4)
I would write some code for this. Maybe that's not what you are looking for but it may help somebody else.)
Solution 1 (This has less code compared with the second solution but second solution's performance is much more better):
public class SubClass extends BaseClass {
private double[] loc;
}
public class BaseClass {
#SerializedName("_id")
private String id;
}
public class CustomTypeAdapter extends TypeAdapter<BaseClass> {
private Gson gson;
public CustomTypeAdapter() {
this.gson = new Gson();
}
#Override
public void write(JsonWriter out, BaseClass value)
throws IOException {
throw new RuntimeException("Not implemented for this question!");
}
#Override
public BaseClass read(JsonReader in) throws IOException {
BaseClass instance;
try {
instance = gson.fromJson(in, SubClass.class);
} catch (Exception e) {
e.printStackTrace();
instance = gson.fromJson(in, BaseClass.class);
}
return instance;
}
}
Test:
private void test() {
String json = "[{_id:\"54b8f62fa08c286b08449b8f\",loc:[36.860983,31.0567]},{_id:\"54b8f6aea08c286b08449b93\",loc:{coordinates:[]}}]";
Type collectionType = new TypeToken<List<BaseClass>>(){}.getType();
Gson gson = new GsonBuilder().registerTypeAdapter(BaseClass.class, new CustomTypeAdapter()).create();
List<BaseClass> list = gson.fromJson(json, collectionType);
for(BaseClass item : list) {
if(item instanceof SubClass) {
System.out.println("item has loc value");
SubClass subClassInstance = (SubClass)item;
} else {
System.out.println("item has no loc value");
BaseClass baseClassInstance = item;
}
}
}
Solution 2 (It is one of the Gson Developers suggestion. See original post.):
Copy below class to your project. It is going to be a base class for your custom TypeAdapterFactorys.
public abstract class CustomizedTypeAdapterFactory<C>
implements TypeAdapterFactory {
private final Class<C> customizedClass;
public CustomizedTypeAdapterFactory(Class<C> customizedClass) {
this.customizedClass = customizedClass;
}
#SuppressWarnings("unchecked") // we use a runtime check to guarantee that 'C' and 'T' are equal
public final <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
return type.getRawType() == customizedClass
? (TypeAdapter<T>) customizeMyClassAdapter(gson, (TypeToken<C>) type)
: null;
}
private TypeAdapter<C> customizeMyClassAdapter(Gson gson, TypeToken<C> type) {
final TypeAdapter<C> delegate = gson.getDelegateAdapter(this, type);
final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
return new TypeAdapter<C>() {
#Override public void write(JsonWriter out, C value) throws IOException {
JsonElement tree = delegate.toJsonTree(value);
beforeWrite(value, tree);
elementAdapter.write(out, tree);
}
#Override public C read(JsonReader in) throws IOException {
JsonElement tree = elementAdapter.read(in);
afterRead(tree);
return delegate.fromJsonTree(tree);
}
};
}
/**
* Override this to muck with {#code toSerialize} before it is written to
* the outgoing JSON stream.
*/
protected void beforeWrite(C source, JsonElement toSerialize) {
}
/**
* Override this to muck with {#code deserialized} before it parsed into
* the application type.
*/
protected void afterRead(JsonElement deserialized) {
}
}
Write your POJO and your custom CustomizedTypeAdapterFactory. Override afterRead method and handle double array as you asked at your question:
public class MyClass {
#SerializedName("_id")
private String id;
private double[] loc;
// getters/setters
}
private class MyClassTypeAdapterFactory extends CustomizedTypeAdapterFactory<MyClass> {
private MyClassTypeAdapterFactory() {
super(MyClass.class);
}
#Override protected void afterRead(JsonElement deserialized) {
try {
JsonArray jsonArray = deserialized.getAsJsonObject().get("loc").getAsJsonArray();
System.out.println("loc is not a double array, its ignored!");
} catch (Exception e) {
deserialized.getAsJsonObject().remove("loc");
}
}
}
Test:
private void test() {
String json = "[{_id:\"54b8f62fa08c286b08449b8f\",loc:[36.860983,31.0567]},{_id:\"54b8f6aea08c286b08449b93\",loc:{coordinates:[]}}]";
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new MyClassTypeAdapterFactory())
.create();
Type collectionType = new TypeToken<List<MyClass>>(){}.getType();
List<MyClass> list = gson.fromJson(json, collectionType);
for(MyClass item : list) {
if(item.getLoc() != null) {
System.out.println("item has loc value");
} else {
System.out.println("item has no loc value");
}
}
}
This is how I did this. It is shorter, but I think #DevrimTuncers answer is the best one.
//This is just Double array to use as location object
public class Location extends ArrayList<Double> {
public Double getLatidute() {
if (this.size() > 0) {
return this.get(0);
} else {
return (double) 0;
}
}
public Double getLongitude() {
if (this.size() > 1) {
return this.get(1);
} else {
return (double) 0;
}
}
public static class LocationDeserializer implements JsonDeserializer<Location> {
#Override
public Location deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
try {
JsonArray array = json.getAsJsonArray();
Location location = new Location();
for (int i = 0; i < array.size(); i++) {
location.add(array.get(i).getAsDouble());
}
return location;
} catch (Exception e) {
return null;
}
}
}
}

javax.ejb.EJBException: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY

GSON Throwing Syntax exception While parsing the JSON into a Java Objects. Here I have attached my JSON and the Classes by which JSON has been parsed and the code where I am parsing the JSON values. Please help me to fix this error.
The following is my JSON Response Which is to be parsed.
JSON
[
{ "counter":1,
"data":{
"b":[
{"d":11.080666011022274,"e":-9.84375},
{"d":21.36033117555945,"e":-13.18359375},
{"d":25.55169302685644,"e":-5.09765625},
{"d":20.209969075006228,"e":24.9609375},
{"d":6.740259027196141,"e":27.7734375},
{"d":19.38301389529031,"e":10.01953125}
],
"gm_accessors_":{"length":null},
"length":6,
"gm_bindings_":{"length":{}}
}
},
{ "counter":2,
"data":{
"b":[
{"d":43.76263306667474,"e":60.1171875},
{"d":56.310038487065135,"e":47.8125},
{"d":60.881999484084055,"e":78.22265625},
{"d":55.81939178481952,"e":96.6796875},
{"d":44.76961886697326,"e":99.84375},
{"d":55.72051189919337,"e":82.08984375},
{"d":40.50489156437503,"e":81.5625},
{"d":52.74250152629922,"e":72.0703125}
],
"gm_accessors_":{"length":null},
"length":8,
"gm_bindings_":{"length":{}}
}
}
]
The Above Json has been parsed by the following JAVA classes. In the following Class structure I am making Mistake. Please guide me where I am doing the mistake.
**Parent Class -- SHAPE**
public class Shape {
#SerializedName("counter")
private Integer mCounter;
#SerializedName("data")
private Data mData;
public Data getmData() {
return mData;
}
public void setmData(Data mData) {
this.mData = mData;
}
public Integer getCounter() {
return mCounter;
}
public void setCounter(Integer counter) {
this.mCounter = counter;
}
}
**CHILD CLASS -- DATA**
public class Data {
#SerializedName("length")
private Integer length;
#SerializedName("b")
private b mCoordinates;
public Integer getLength() {
return length;
}
public void setLength(Integer length) {
this.length = length;
}
public b getmCoordinates() {
return mCoordinates;
}
public void setmCoordinates(b mCoordinates) {
this.mCoordinates = mCoordinates;
}
}
**GRAND CHILD CLASS -- b**
public class b {
#SerializedName("d")
private ArrayList<Float> lattitude;
#SerializedName("e")
private ArrayList<Float> longtitude;
public ArrayList<Float> getLattitude() {
return lattitude;
}
public void setLattitude(ArrayList<Float> lattitude) {
this.lattitude = lattitude;
}
public ArrayList<Float> getLongtitude() {
return longtitude;
}
public void setLongtitude(ArrayList<Float> longtitude) {
this.longtitude = longtitude;
}
}
JSON PARSING -- CHANGING JSON AS A JAVA OBJECTS
JsonParser parser = new JsonParser();
JsonArray jArray = parser.parse(jsonContent).getAsJsonArray();
System.out.println("Array :_: " + jArray);
for(JsonElement jsonElement : jArray) {
System.out.println("JSON_ELEMENT :_: " + jsonElement);
Shape shape = gson.fromJson(jsonElement, Shape.class);
System.out.println("Counter :_: " + shape.getCounter());
}
Please chnage your data class to :
public class Data {
#SerializedName("length")
private Integer length;
#SerializedName("b")
// this is where the error was thrown,
// it was expecting an array but only received a single object.
private List<b> mCoordinates;
public Integer getLength() {
return length;
}
public void setLength(Integer length) {
this.length = length;
}
public List<b> getmCoordinates() {
return mCoordinates;
}
public void setmCoordinates(List<b> mCoordinates) {
this.mCoordinates = mCoordinates;
}
}
And also change the b class to:
public class b {
#SerializedName("d")
private double d;
#SerializedName("e")
private double e;
public double getD() {
return d;
}
public void setD(double d) {
this.d = d;
}
public double getE() {
return e;
}
public void setE(double e) {
this.e = e;
}
}
use:
Gson gson = new Gson();
Shape shape = gson.fromJson(reader/string here, Shape.class);
and your shape class will be filled.
public class Shape {
#SerializedName("counter")
private Integer mCounter;
#SerializedName("data")
private Data mData;
// geter/setter here
}
public class Data {
#SerializedName("length")
private Integer length;
#SerializedName("b")
private List<Coordinate> coordinates;
#SerializedName("gm_accessors_")
private Accessors gmAccessors;
//getter setter here
}
public class Coordinate {
private float d;
private float e;
}
public class Accessors {
private Integer length;
}
Finally Parse it as
Shape[] shapes = gson.fromJson(jArray, Shape[].class);
If you will parse like this you will get same error : Expected BEGIN_OBJECT but was BEGIN_ARRAY
Shape shape = gson.fromJson(jArray, Shape.class);

Store enums in database using hibernate

I need to store an object using Hibernate, but this object use an enum. I can store, but when I tried to retrieve it again, this fails with this error: "Studies is not mapped [FROM Studies]".
I tried with a lot of solutions in internet but nothing works. I use MySQL database
This is the enum:
public enum StudyStatus {
Created("Created"), Started("Started"), Closed("Closed");
private final String value;
StudyStatus(String value){
this.value = value;
}
public static StudyStatus fromValue(int value){
for (StudyStatus status : values()) {
if (status.value.equals(value)) {
return status;
}
}
throw new IllegalArgumentException("Invalid status: " + value);
}
public String toValue(){
return value;
}
}
This is the EnumUserType class
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Properties;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.type.AbstractStandardBasicType;
import org.hibernate.type.IntegerType;
import org.hibernate.type.StringType;
import org.hibernate.usertype.EnhancedUserType;
import org.hibernate.usertype.ParameterizedType;
public abstract class AbstractEnumUserType<E extends Enum<E>, V> implements
EnhancedUserType, ParameterizedType {
public static int DEAFAULT_SQL_TYPE = Types.INTEGER;
private PreparedStatementSetter psSetter;
private AbstractStandardBasicType<?> basicType;
protected abstract Class<E> getEnumClass();
protected abstract Class<V> getValueClass();
protected abstract E convertEnum(V rawValue);
protected abstract V convertSqlValue(E enumValue);
protected int getSqlType() {
int sqlType = Types.OTHER;
switch (getValueClass().getName()) {
case "java.lang.String":
sqlType = Types.VARCHAR;
break;
case "java.lang.Integer":
sqlType = Types.INTEGER;
break;
default:
break;
}
return sqlType;
}
// ////////////////////////////
#Override
public int[] sqlTypes() {
return new int[] { getSqlType() };
}
#Override
public Class<?> returnedClass() {
return getEnumClass();
}
#Override
public boolean equals(Object x, Object y) throws HibernateException {
return (x == y);
}
#Override
public int hashCode(Object x) throws HibernateException {
return (x == null) ? 0 : x.hashCode();
}
#Override
public Object nullSafeGet(ResultSet rs, String[] names,
SessionImplementor session, Object owner)
throws HibernateException, SQLException {
Object rawValue = basicType.nullSafeGet(rs, names[0], session, owner);
Object enumValue = (rawValue == null) ? null
: convertEnum((V) rawValue);
return enumValue;
}
#Override
public void nullSafeSet(PreparedStatement st, Object value, int index,
SessionImplementor session) throws HibernateException, SQLException {
if (value == null) {
st.setNull(index, Types.VARCHAR);
} else {
psSetter.set(st, convertSqlValue((E) value), index);
}
}
#Override
public Object deepCopy(Object value) throws HibernateException {
return value;
}
#Override
public boolean isMutable() {
return false;
}
#Override
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value;
}
#Override
public Object assemble(Serializable cached, Object owner)
throws HibernateException {
return cached;
}
#Override
public Object replace(Object original, Object target, Object owner)
throws HibernateException {
return original;
}
#Override
public void setParameterValues(Properties parameters) {
// Initialize Method
initBasicType();
initPreparedStatementSetter();
}
#Override
public String objectToSQLString(Object value) {
return '\'' + ((Enum<?>) value).name() + '\'';
}
#Override
public String toXMLString(Object value) {
return ((Enum<?>) value).name();
}
#Override
public Object fromXMLString(String xmlValue) {
// TODO
throw new IllegalAccessError();
// return Enum.valueOf(, xmlValue);
}
protected void initBasicType() {
switch (getSqlType()) {
case Types.VARCHAR:
basicType = StringType.INSTANCE;
break;
case Types.INTEGER:
basicType = IntegerType.INSTANCE;
break;
default:
break;
}
}
protected void initPreparedStatementSetter() {
// TODO
switch (getSqlType()) {
case Types.VARCHAR:
psSetter = new StringPreparedStatementSetter();
break;
case Types.INTEGER:
psSetter = new IntPreparedStatementSetter();
default:
break;
}
}
private static interface PreparedStatementSetter {
void set(PreparedStatement st, Object value, int index)
throws SQLException;
}
private static class StringPreparedStatementSetter implements
PreparedStatementSetter {
#Override
public void set(PreparedStatement st, Object value, int index) {
try {
st.setString(index, (String) value);
} catch (SQLException e) {
}
}
}
private static class IntPreparedStatementSetter implements
PreparedStatementSetter {
#Override
public void set(PreparedStatement st, Object value, int index) {
try {
st.setInt(index, (Integer) value);
} catch (SQLException e) {
}
}
}
}
The class with the enum
import java.util.ArrayList;
import ateam.capi.common.enums.StudyStatus;
public class Study {
private String id;
private String name;
private StudyStatus status;
private ArrayList<User> pollsters;
private Questionnaire actualQuestionnaire;
public Questionnaire getActualQuestionnaire() {
return actualQuestionnaire;
}
public void setActualQuestionnaire(Questionnaire actualQuestionnaire) {
this.actualQuestionnaire = actualQuestionnaire;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public StudyStatus getStatus() {
return status;
}
public void setStatus(StudyStatus status) {
this.status = status;
}
public ArrayList<User> getPollsters() {
return pollsters;
}
public void setPollsters(ArrayList<User> pollsters) {
this.pollsters = pollsters;
}
}
This is the XML to map the Study class
<hibernate-mapping package="ateam.capi.common.beans">
<class name="Study" table="Studies">
<id name="id" column="id"></id>
<property name="name"/>
<property name="status">
<type name="ateam.capi.capipersistence.utils.EnumUserType">
<param name="enumClassName">
ateam.capi.common.enums.StudyStatus
</param>
</type>
</property>
</class>
</hibernate-mapping>
Study DAO class
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import ateam.capi.capipersistence.utils.HibernateUtil;
import ateam.capi.common.beans.Questionnaire;
import ateam.capi.common.beans.Study;
public class DAO_Study {
private Session session;
private Transaction tx;
public void saveStudy(Study study) throws HibernateException{
try{
initOperations();
session.save(study);
tx.commit();
} catch (HibernateException ex){
handleException(ex);
throw ex;
} finally{
if (session!=null){
session.close();
}
}
}
public void deleteStudy(Study study) throws HibernateException{
try{
initOperations();
this.session.delete(study);
this.tx.commit();
} catch (HibernateException ex){
handleException(ex);
throw ex;
} finally{
if (session!=null){
session.close();
}
}
}
public List<Study> getStudiesList() throws HibernateException{
List<Study> studiesList = null;
try{
initOperations();
String hql = "FROM Studies";
Query query = session.createQuery(hql);
studiesList = query.list();
} catch (HibernateException ex){
handleException(ex);
throw ex;
} finally{
if (session!=null){
session.close();
}
}
return studiesList;
}
private void initOperations() throws HibernateException{
HibernateUtil.createSession();
this.session = HibernateUtil.getSessionFactory().openSession();
this.tx = this.session.beginTransaction();
}
private void handleException(HibernateException ex) throws HibernateException{
this.tx.rollback();
System.out.println(ex.getStackTrace());
throw ex;
}
}
I use Java7 with hibernate 4.1.8, I found other solutions but dont work in java7
Any Idea?
Thanks!
Shouldn't your query look like from study instead of from studies? Studies is the table not the defined entity.

Jackson readValue mapping to overloaded java class problem

I have some JSON where one of the keys has one of three values: an int, a string, or a json object. Using the snippet below I can map this field when it is an int or a string but fail when it's a json object. Where am I going wrong? What should I be doing?
The JSON value key looks like:
"value": 51,
or
"value": 51,
or (and this is where I am having trouble)
"value": {"lat": 53.990614999999998, "lng": -1.5391117000000301, "addr": "Harrogate, North Yorkshire, UK"}
public class Test {
public Test() {
}
public static class Value {
public int slidervalue;
public String voicevalue;
public GeoValue geovalue; // problem
public Value(int value) {
this.slidervalue = value
}
public Value(String value) {
this.voicevalue = value;
}
public Value(JSONObject value) {
JSONObject foo = value; // this is never reached
this.geovalue = value; // and how would this work so as map value to a GeoValue?
}
private static class GeoValue {
private double _lat;
private double _lng;
private String _addr;
public float getLat() {
return (float)_lat;
}
public void setLat(float lat) {
_lat = (double)lat;
}
public float getLng() { return (float)_lng;}
public void setLng(float lng) { _lng = (double)lng; }
public String getAddr() { return _addr;}
public void setAddr(String addr) { _addr = addr; }
}
} // end of Value class
public Value getValue() { return _value;}
public void setValue(Value value) {
_value = value;
}
} //end of Test class
and this is being used like this:
ObjectMapper mapper = new ObjectMapper();
instance = mInstances.getJSONObject(i).toString();
Test testinstance = mapper.readValue(instance, Test.class);
public class Test {
public Test() {
}
public static class Value {
public int slidervalue;
public String voicevalue;
public GeoValue geovalue; // problem
public Value(int value) {
this.slidervalue = value
}
public Value(String value) {
this.voicevalue = value;
}
public Value(JSONObject value) {
JSONObject foo = value; // this is never reached
this.geovalue = value; // and how would this work so as map value to a GeoValue?
}
private static class GeoValue {
private double _lat;
private double _lng;
private String _addr;
public float getLat() {
return (float)_lat;
}
public void setLat(float lat) {
_lat = (double)lat;
}
public float getLng() { return (float)_lng;}
public void setLng(float lng) { _lng = (double)lng; }
public String getAddr() { return _addr;}
public void setAddr(String addr) { _addr = addr; }
}
} // end of Value class
public Value getValue() { return _value;}
public void setValue(Value value) {
_value = value;
}
} //end of Test class
and this is being used like this:
ObjectMapper mapper = new ObjectMapper();
instance = mInstances.getJSONObject(i).toString();
Test testinstance = mapper.readValue(instance, Test.class);
This fails with a JSONMappingException: No suitable contructor found for type ... 'value'
Thanks. Alex
What might work is that you mark the constructor that takes JSONObject with #JsonCreator, but do NOT add #JsonProperty for the single parameter. In that case, incoming JSON is bound to type of that parameter (in this case JSONObject, but you could use Map as well), and passed to constructor.
Overloading still works because of special handling for single-string/int/long-argument constructor.
I am not sure if that is the cleanest solution; it might be cleanest to just implement custom deserializer. But it should work.
If your code is what you want, your json should be like this:
{"value":{"slidervalue":1,"voicevalue":"aa","geovalue":{"lat":53.990615,"lng":-1.53911170000003,"addr":"Harrogate, North Yorkshire, UK"}}}

Casting an object using 'as' returns null: myObject = newObject as MyObject; // null

I am trying to create a custom object in AS3 to pass information to and from a server, which in this case will be Red5. In the below screenshots you will see that I am able to send a request for an object from as3, and receive it successfully from the java server. However, when I try to cast the received object to my defined objectType using 'as', it takes the value of null. It is my understanding that that when using "as" you're checking to see if your variable is a member of the specified data type. If the variable is not, then null will be returned.
This screenshot illustrates that I am have successfully received my object 'o' from red5 and I am just about to cast it to the (supposedly) identical datatype testObject of LobbyData:
Enlarge
However, when testObject = o as LobbyData; runs, it returns null. :(
Enlarge
Below you will see my specifications both on the java server and the as3 client. I am confident that both objects are identical in every way, but for some reason flash does not think so. I have been pulling my hair out for a long time, does anyone have any thoughts?
AS3 Object:
import flash.utils.IDataInput;
import flash.utils.IDataOutput;
import flash.utils.IExternalizable;
import flash.net.registerClassAlias;
[Bindable]
[RemoteClass(alias = "myLobbyData.LobbyData")]
public class LobbyData implements IExternalizable
{
private var sent:int; // java sentinel
private var u:String; // red5 username
private var sen:int; // another sentinel?
private var ui:int; // fb uid
private var fn:String; // fb name
private var pic:String; // fb pic
private var inb:Boolean; // is in the table?
private var t:int; // table number
private var s:int; // seat number
public function setSent(sent:int):void
{
this.sent = sent;
}
public function getSent():int
{
return sent;
}
public function setU(u:String):void
{
this.u = u;
}
public function getU():String
{
return u;
}
public function setSen(sen:int):void
{
this.sen = sen;
}
public function getSen():int
{
return sen;
}
public function setUi(ui:int):void
{
this.ui = ui;
}
public function getUi():int
{
return ui;
}
public function setFn(fn:String):void
{
this.fn = fn;
}
public function getFn():String
{
return fn;
}
public function setPic(pic:String):void
{
this.pic = pic;
}
public function getPic():String
{
return pic;
}
public function setInb(inb:Boolean):void
{
this.inb = inb;
}
public function getInb():Boolean
{
return inb;
}
public function setT(t:int):void
{
this.t = t;
}
public function getT():int
{
return t;
}
public function setS(s:int):void
{
this.s = s;
}
public function getS():int
{
return s;
}
public function readExternal(input:IDataInput):void
{
sent = input.readInt();
u = input.readUTF();
sen = input.readInt();
ui = input.readInt();
fn = input.readUTF();
pic = input.readUTF();
inb = input.readBoolean();
t = input.readInt();
s = input.readInt();
}
public function writeExternal(output:IDataOutput):void
{
output.writeInt(sent);
output.writeUTF(u);
output.writeInt(sen);
output.writeInt(ui);
output.writeUTF(fn);
output.writeUTF(pic);
output.writeBoolean(inb);
output.writeInt(t);
output.writeInt(s);
}
}
Java Object:
package myLobbyData;
import org.red5.io.amf3.IDataInput;
import org.red5.io.amf3.IDataOutput;
import org.red5.io.amf3.IExternalizable;
public class LobbyData implements IExternalizable
{
private static final long serialVersionUID = 115280920;
private int sent; // java sentinel
private String u; // red5 username
private int sen; // another sentinel?
private int ui; // fb uid
private String fn; // fb name
private String pic; // fb pic
private Boolean inb; // is in the table?
private int t; // table number
private int s; // seat number
public void setSent(int sent)
{
this.sent = sent;
}
public int getSent()
{
return sent;
}
public void setU(String u)
{
this.u = u;
}
public String getU()
{
return u;
}
public void setSen(int sen)
{
this.sen = sen;
}
public int getSen()
{
return sen;
}
public void setUi(int ui)
{
this.ui = ui;
}
public int getUi()
{
return ui;
}
public void setFn(String fn)
{
this.fn = fn;
}
public String getFn()
{
return fn;
}
public void setPic(String pic)
{
this.pic = pic;
}
public String getPic()
{
return pic;
}
public void setInb(Boolean inb)
{
this.inb = inb;
}
public Boolean getInb()
{
return inb;
}
public void setT(int t)
{
this.t = t;
}
public int getT()
{
return t;
}
public void setS(int s)
{
this.s = s;
}
public int getS()
{
return s;
}
#Override
public void readExternal(IDataInput input)
{
sent = input.readInt();
u = input.readUTF();
sen = input.readInt();
ui = input.readInt();
fn = input.readUTF();
pic = input.readUTF();
inb = input.readBoolean();
t = input.readInt();
s = input.readInt();
}
#Override
public void writeExternal(IDataOutput output)
{
output.writeInt(sent);
output.writeUTF(u);
output.writeInt(sen);
output.writeInt(ui);
output.writeUTF(fn);
output.writeUTF(pic);
output.writeBoolean(inb);
output.writeInt(t);
output.writeInt(s);
}
}
AS3 Client:
public function refreshRoom(event:Event)
{
var resp:Responder=new Responder(handleResp,null);
ncLobby.call("getLobbyData", resp, null);
}
public function handleResp(o:Object):void
{
var testObject:LobbyData=new LobbyData;
testObject = o as LobbyData;
trace(testObject);
}
Java Client
public LobbyData getLobbyData(String param)
{
LobbyData lobbyData1 = new LobbyData();
lobbyData1.setSent(5);
lobbyData1.setU("lawlcats");
lobbyData1.setSen(5);
lobbyData1.setUi(5);
lobbyData1.setFn("lulz");
lobbyData1.setPic("lulzagain");
lobbyData1.setInb(true);
lobbyData1.setT(5);
lobbyData1.setS(5);
return lobbyData1;
}
As you already figured out, you should use registerClassAlias as the RemoteClass works out of the box only for Flex projects (as bindable, etc).
Be sure to call registerClassAlias before any serializing / deserializing occurs.
Also, the debugger is showing you the actual tipe of your "o" parameter, which is object. This shows that the player is not correctly mapping the AMF serialized object's class to any of your classes (so, by default, it goes with Object). You should see a LobbyData object in the debugger; otherwise, no matter how you cast / coerce it, it won't work.
The objet needs to be declared before the responder is called.
public function refreshRoom(event:Event)
{
var testObject:LobbyData=new LobbyData;
var resp:Responder=new Responder(handleResp,null);
ncLobby.call("getLobbyData", resp, null);
}
public function handleResp(o:Object):void
{
testObject = o as LobbyData;
trace(testObject);
}
Actually if you want to workaround the type casting you can simply add this to your constructor:
public function dataAwareObject(o:* = null)
{
//TODO: implement function
super();
if(o){
for(var a:* in o)
this[a] = o[a];
}
}
}
Works like a charm.