I'm trying to implement Writable class, but i have no idea on how to implement a writable class if in my class there is nested object, such as list, etc. Could any body help me? thanks
public class StorageClass implements Writable{
public String xStr;
public String yStr;
public List<Field> sStor
//omitted ctors
#override
public void write(DataOutput out) throws IOException{
out.writeChars(xStr);
out.WriteChars(yStr);
//WHAT SHOULD I DO FOR List<Field>
}
#override
public void readFields(DataInput in) throws IOException{
xStr = in.readLine();
yStr = in.readLine();
//WHAT SHOULD I DO FOR List<Field>
}
}
public class SubStorage{
public String x;
public String y;
}
}
Following is the Field class:
public final class Field implements Comparable<Field>, Serializable {
private String name;
private DataType dataType;
private Object value;
private FieldType fieldType;
public Field(){
}
public Field(String name, DataType dataType, FieldType fieldType){
this(name, dataType, null, fieldType);
}
public Field(String name, DataType type, Object value, FieldType fieldType){
this.name = name;
this.dataType = type;
this.value = value;
this.fieldType = fieldType;
}
}
public enum FieldType {
PRI, LOOKUP, SCD, VERSION, OTHER
}
public enum DataType {
UNDEFINED(4) {
public int getSizeInBytes(Object value) {
return STRING.getSizeInBytes(value);
}
},
STRING(4) {
public int getSizeInBytes(Object value) {
if (value == null) {
return 0;
}
return super.getSizeInBytes(value) + (value.toString().length() * 2); // length + chars
}
},
INT(4),
LONG(8),
DOUBLE(8),
DATETIME(8),
BOOLEAN(1),
BYTE(1),
FLOAT(4),
SHORT(2),
CHAR(2),
DATE(8),
TIME(8),
BLOB(0) {
public int getSizeInBytes(Object value) {
if (value == null) {
return 0;
}
return ((byte[])value).length;
}
};
private final int sizeInBytes;
private DataType(int sizeInBytes) {
this.sizeInBytes = sizeInBytes;
}
public int getSizeInBytes(Object value) {
return sizeInBytes;
}
}
Serializing collections is quite simple.
#Override
public void readFields(DataInput in) throws IOException {
int size = in.readInt();
list= new ArrayList<Field>(size);
for(int i = 0; i < size; i++){
Field f = new Field();
f.readFields(in);
list.add(f);
}
}
#Override
public void write(DataOutput out) throws IOException {
out.writeInt(list.size());
for (Field l : list) {
l.write(out);
}
}
Field has to implement Writable as well.
This tutorial explains better : http://www.hadoopmaterial.com/2013/10/custom-hadoop-writable-data-type.html
Related
sorry, but I couldn't find a solution to this:
I got this coalesce method which has been working fine for two single values, but I would like to extend it to iterate through any object and return a new object after applying the coalesce in all fields. I wanted to do it with generics, so it work with any given object type.
This is the coalesce method:
public static <T> T coalesce(T one, T two) {
return one != null ? one : two;
}
The idea is to improve to method like this:
public static <T,Z> T coalesceAll(T one, T two) {
T finalObject;
for (Z field : getFields(one.getClass())) {
finalObject.field = coalesce(one.field, two.field);
}
return finalObject;
}
Any idea on how to implement this in Java? Thanks in advance!
I would do this by delegating the coalescing to the actual classes. Making this generic via reflection might be possible but way more complicated:
Coalesce.java
public interface Coalesce<T> {
T coalesce(T other);
default <V> V coalesce(V one, V two) {
return one != null ? one : two;
}
}
Person.java
public class Person implements Coalesce<Person> {
private final Integer id;
private final String name;
public Person(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
#Override
public Person coalesce(Person other) {
final int id = coalesce(this.id, other.id);
final String name = coalesce(this.name, other.name);
return new Person(id, name);
}
}
Book.java
public class Book implements Coalesce<Book> {
private final String title;
private final String author;
public Book(String title, String author) {
this.title = title;
this.author = author;
}
public String getTitle() {
return title;
}
public String getAuthor() {
return author;
}
#Override
public Book coalesce(Book other) {
final String title = coalesce(this.title, other.title);
final String author = coalesce(this.author, other.author);
return new Book(title, author);
}
}
Main.java
public class Main {
public static void main(String[] args) {
final Person personA = new Person(1, null);
final Person personB = new Person(2, "Bob");
final Person coalescedPerson = personA.coalesce(personB);
System.out.println(coalescedPerson.getId()); // 1
System.out.println(coalescedPerson.getName()); // Bob
final Book bookA = new Book(null, "J. R. R. Tolkien");
final Book bookB = new Book("The Hobbit", null);
final Book coalescedBook = bookA.coalesce(bookB);
System.out.println(coalescedBook.getTitle()); // The Hobbit
System.out.println(coalescedBook.getAuthor()); // J. R. R. Tolkien
}
}
I like more the answer by Smutje. But I also like reflection (a lot!).
EDIT: As #fluffy pointed out, in the comments, my old code failed for inherited fields; also I observed that it will not work with primitive value (like int or double).
So I decided to recreate it!, now works with primitive and class inheritance.
The coalesce code
private static void doCoalesce(Field field, Object src, Object target) throws ReflectiveOperationException {
// remove "protection" (for private & final fields)
boolean isAccessible = field.isAccessible();
field.setAccessible(true);
// Copy value if null or default primitive value (0 - zero)
if (isNull(field.getType(), field.get(target))) {
field.set(target, field.get(src));
}
// restore "protection"
field.setAccessible(isAccessible);
}
private static void doCoalesceByClass(Object src, Object target, Class cls) throws ReflectiveOperationException {
for (Field field : cls.getDeclaredFields()) {
doCoalesce(field, src, target);
}
}
private static void doCoalesce(Object src, Object target) throws ReflectiveOperationException {
Class cls = target.getClass();
while (cls != Object.class) {
doCoalesceByClass(src, target, cls);
cls = cls.getSuperclass();
}
}
public static Object coalesce(Object... objects) throws ReflectiveOperationException {
switch (objects.length) {
case 0: return null;
case 1: return objects[0];
default: throwExceptionIfDifferentClass(objects); break;
}
Object finalObject = instantiateDefaultClass(objects[0].getClass());
for (Object object : objects) {
doCoalesce(object, finalObject);
}
return finalObject;
}
The auxiliary code
private static Object instantiateDefaultClass(Class cls) throws ReflectiveOperationException {
final Constructor constructor = cls.getConstructors()[0];
final List<Object> params = new ArrayList<>();
for (Class<?> pType : constructor.getParameterTypes()) {
params.add((pType.isPrimitive()) ? 0 : null);
}
return constructor.newInstance(params.toArray());
}
private static void throwExceptionIfDifferentClass(Object... objects) {
Class cls = objects[0].getClass();
for (Object obj : objects) {
if (obj.getClass() != cls) {
throw new IllegalArgumentException("Objects MUST be of the same class");
}
}
}
private static boolean isNull(Class cls, Object value) {
if (!cls.isPrimitive()) {
return value == null;
}
// Primitive types
if (cls == Boolean.TYPE) return (boolean) value;
if (cls == Byte.TYPE) return (byte) value == 0;
if (cls == Character.TYPE) return (char) value == 0;
if (cls == Short.TYPE) return (short) value == 0;
if (cls == Long.TYPE) return (long) value == 0;
if (cls == Double.TYPE) return (double) value == 0;
if (cls == Float.TYPE) return (float) value == 0;
return false;
}
The test code
public static class Book
{
public final String title;
public final String author;
public final long isbn;
public Book(String title, String author, long isbn) {
this.title = title;
this.author = author;
this.isbn = isbn;
}
}
public static class AudioBook extends Book
{
public final String url;
public AudioBook(String title, String author, long isbn, String url) {
super(title, author, isbn);
this.url = url;
}
}
public static void main(String[] args) throws ReflectiveOperationException {
AudioBook b1 = new AudioBook(null, "J. R. R. Tolkien", 9780261103306L, null);
AudioBook b2 = new AudioBook("The Hobbit", null, 0, "www.thehobbit.com");
AudioBook finalBook = (AudioBook) coalesce(b1, b2);
System.out.println(finalBook.author + ", " + finalBook.title + ", " + finalBook.isbn + ", " + finalBook.url);
}
I have like this json.I'm using Gson to parse it and convert it in my custom class object.Here is a my java classes
public class ResponseModel {
private int resultCode;
private Match match;
public Match getMatch() {
return match;
}
public int getResultCode() {
return resultCode;
}
}
public class Match {
private Team team1;
private Team team2;
private double matchTime;
public Team getTeam1() {
return team1;
}
public Team getTeam2() {
return team2;
}
private Long matchDate;
private String stadiumAdress;
public double getMatchTime() {
return matchTime;
}
public Long getMatchDate() {
return matchDate;
}
public String getStadiumAdress() {
return stadiumAdress;
}
}
public class Team {
private String teamName;
private String teamImage;
public String getTeamName() {
return teamName;
}
public void setTeamName(String teamName) {
this.teamName = teamName;
}
public String getTeamImage() {
return teamImage;
}
public void setTeamImage(String teamImage) {
this.teamImage = teamImage;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public int getBallPosition() {
return ballPosition;
}
public void setBallPosition(int ballPosition) {
this.ballPosition = ballPosition;
}
private int score;
private int ballPosition;
}
I'm using Gson like this
ResponseModel responseModel = GsonUtil.fromJson(response.toString(), ResponseModel.class);
public class GsonUtil {
public static <T> T fromJson(String json, Class<T> c) {
return new Gson().fromJson(json, c);
}
public static String toJson(Object c) {
return new Gson().toJson(c);
}
}
Everything working perfect,I can convert my json to custom class.But I want to use enum class with team1 and team2. My goal is to convert like this enum class
MatchTeamType:
TEAM1 (1);
TEAM2 (2);
How I can rewrite my code with enum class?
Thanks
I'm working on a project where I'm integrating with a 3rd party service that returns a JSON response. I am using Jackson to deserialize the response into a Java POJO. The response is an object that has a few simple fields that Jackson is able to easily parse. However the response also contains an array with a single entry that is also an object. When Jackson attempts to deserialize it I get the top level object containing a list with the single entry in the list, however all of the fields for the single entry in the list are null. Any idea what I'm doing wrong here?
UPDATE: after setting FAIL_ON_UNKNOWN_PROPERTIES to true, I am getting the following stack trace. Still not sure why it is having issues with the wrapped "RecurringDetail" object in the array.
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "RecurringDetail" (class com.adyen.www.models.RecurringDetail), not marked as ignorable (19 known properties: "variant", "contractTypes", "tokenDetails", "aliasType", "name", "creationDate", "firstPspReference", "elv", "card", "additionalData", "shopperName", "socialSecurityNumber", "billingAddress", "bank", "recurringDetailReference", "paymentMethodVariant", "alias", "acquirer", "acquirerAccount"])
at [Source: response.json; line: 5, column: 33] (through reference chain: com.adyen.www.models.RecurringDetailsResult["details"]->java.util.ArrayList[0]->com.adyen.www.models.RecurringDetail["RecurringDetail"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:62)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:834)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1094)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1470)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1448)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:282)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:287)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:259)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:26)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:499)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:101)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:276)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3798)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2759)
JSON
{
"creationDate": "2017-01-26T23:11:20+01:00",
"details": [
{
"RecurringDetail": {
"acquirer": "TestPmmAcquirer",
"acquirerAccount": "TestPmmAcquirerAccount",
"additionalData": {
"cardBin": "440000"
},
"alias": "B133243153928547",
"aliasType": "Default",
"card": {
"expiryMonth": "8",
"expiryYear": "2018",
"holderName": "Steve HAll",
"number": "0008"
},
"contractTypes": [
"RECURRING"
],
"creationDate": "2017-01-26T23:11:20+01:00",
"firstPspReference": "8524854686798738",
"paymentMethodVariant": "visadebit",
"recurringDetailReference": "8414854686802111",
"variant": "visa"
}
}
],
"invalidOneclickContracts": "false",
"lastKnownShopperEmail": "someones#email.com",
"shopperReference": "xggZcGauSSG5jP+akIlijQ=="
}
Unit Test
public class RecurringDetailResultTest {
public static ObjectMapper mapper = new ObjectMapper()
{
private static final long serialVersionUID = -174113593500315394L;
{
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
configure(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS, true);
setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
};
#Test
public void testParseRecurringDetailResulte() throws IOException {
RecurringDetailsResult result = mapper.readValue(new File("response.json"), new TypeReference<RecurringDetailsResult>(){});
if (result.getDetails() != null && !result.getDetails().isEmpty()) {
RecurringDetail detail = result.getDetails().get(0);
if (StringUtils.isEmpty(detail.getRecurringDetailReference())) {
fail("Recurring detail does not contain any information.");
}
} else {
fail("No result details returned.");
}
}
}
Model (Root object)
public class RecurringDetailsResult
implements java.io.Serializable {
private static final long serialVersionUID = 5297684963950973136L;
private Date creationDate;
private String shopperReference;
private List<RecurringDetail> details;
private String lastKnownShopperEmail;
#JsonGetter("creationDate")
public Date getCreationDate ( ) {
return this.creationDate;
}
#JsonSetter("creationDate")
public void setCreationDate (Date value) {
this.creationDate = value;
}
#JsonGetter("shopperReference")
public String getShopperReference ( ) {
return this.shopperReference;
}
#JsonSetter("shopperReference")
public void setShopperReference (String value) {
this.shopperReference = value;
}
#JsonGetter("details")
public List<RecurringDetail> getDetails ( ) {
return this.details;
}
#JsonSetter("details")
public void setDetails (List<RecurringDetail> value) {
this.details = value;
}
#JsonGetter("lastKnownShopperEmail")
public String getLastKnownShopperEmail ( ) {
return this.lastKnownShopperEmail;
}
#JsonSetter("lastKnownShopperEmail")
public void setLastKnownShopperEmail (String value) {
this.lastKnownShopperEmail = value;
}
}
Model (the object in the array, all of the fields of this guy are null when Jackson deserializes the JSON)
public class RecurringDetail
implements java.io.Serializable {
private static final long serialVersionUID = 5302883242997268343L;
private String name;
private Date creationDate;
private Card card;
private ELV elv;
private Address billingAddress;
private String additionalData;
private Name shopperName;
private String socialSecurityNumber;
private String recurringDetailReference;
private BankAccount bank;
private String alias;
private String aliasType;
private TokenDetails tokenDetails;
private String variant;
private String paymentMethodVariant;
private String firstPspReference;
private List<String> contractTypes;
private String acquirer;
private String acquirerAccount;
#JsonGetter("name")
public String getName ( ) {
return this.name;
}
#JsonSetter("name")
public void setName (String value) {
this.name = value;
}
#JsonGetter("creationDate")
public Date getCreationDate ( ) {
return this.creationDate;
}
#JsonSetter("creationDate")
public void setCreationDate (Date value) {
this.creationDate = value;
}
#JsonGetter("card")
public Card getCard ( ) {
return this.card;
}
#JsonSetter("card")
public void setCard (Card value) {
this.card = value;
}
#JsonGetter("elv")
public ELV getElv ( ) {
return this.elv;
}
#JsonSetter("elv")
public void setElv (ELV value) {
this.elv = value;
}
#JsonGetter("billingAddress")
public Address getBillingAddress ( ) {
return this.billingAddress;
}
#JsonSetter("billingAddress")
public void setBillingAddress (Address value) {
this.billingAddress = value;
}
#JsonGetter("additionalData")
public String getAdditionalData ( ) {
return this.additionalData;
}
#JsonSetter("additionalData")
public void setAdditionalData (String value) {
this.additionalData = value;
}
#JsonGetter("shopperName")
public Name getShopperName ( ) {
return this.shopperName;
}
#JsonSetter("shopperName")
public void setShopperName (Name value) {
this.shopperName = value;
}
#JsonGetter("socialSecurityNumber")
public String getSocialSecurityNumber ( ) {
return this.socialSecurityNumber;
}
#JsonSetter("socialSecurityNumber")
public void setSocialSecurityNumber (String value) {
this.socialSecurityNumber = value;
}
#JsonGetter("recurringDetailReference")
public String getRecurringDetailReference ( ) {
return this.recurringDetailReference;
}
#JsonSetter("recurringDetailReference")
public void setRecurringDetailReference (String value) {
this.recurringDetailReference = value;
}
#JsonGetter("bank")
public BankAccount getBank ( ) {
return this.bank;
}
#JsonSetter("bank")
public void setBank (BankAccount value) {
this.bank = value;
}
#JsonGetter("alias")
public String getAlias ( ) {
return this.alias;
}
#JsonSetter("alias")
public void setAlias (String value) {
this.alias = value;
}
#JsonGetter("aliasType")
public String getAliasType ( ) {
return this.aliasType;
}
#JsonSetter("aliasType")
public void setAliasType (String value) {
this.aliasType = value;
}
#JsonGetter("tokenDetails")
public TokenDetails getTokenDetails ( ) {
return this.tokenDetails;
}
#JsonSetter("tokenDetails")
public void setTokenDetails (TokenDetails value) {
this.tokenDetails = value;
}
#JsonGetter("variant")
public String getVariant ( ) {
return this.variant;
}
#JsonSetter("variant")
public void setVariant (String value) {
this.variant = value;
}
#JsonGetter("paymentMethodVariant")
public String getPaymentMethodVariant ( ) {
return this.paymentMethodVariant;
}
#JsonSetter("paymentMethodVariant")
public void setPaymentMethodVariant (String value) {
this.paymentMethodVariant = value;
}
#JsonGetter("firstPspReference")
public String getFirstPspReference ( ) {
return this.firstPspReference;
}
#JsonSetter("firstPspReference")
public void setFirstPspReference (String value) {
this.firstPspReference = value;
}
#JsonGetter("contractTypes")
public List<String> getContractTypes ( ) {
return this.contractTypes;
}
#JsonSetter("contractTypes")
public void setContractTypes (List<String> value) {
this.contractTypes = value;
}
#JsonGetter("acquirer")
public String getAcquirer ( ) {
return this.acquirer;
}
#JsonSetter("acquirer")
public void setAcquirer (String value) {
this.acquirer = value;
}
#JsonGetter("acquirerAccount")
public String getAcquirerAccount ( ) {
return this.acquirerAccount;
}
#JsonSetter("acquirerAccount")
public void setAcquirerAccount (String value) {
this.acquirerAccount = value;
}
}
The easiest thing I can think to do is to make your java objects look like your Json. Because this Json has a wrapped inner object but not the outer object you would have to have a similar wrapping in java. It isn't elegant but works.
public class RecurringDetailsResult implements java.io.Serializable {
private Date creationDate;
private String shopperReference;
private List<RecurringDetailWrapper> details;
private String lastKnownShopperEmail;
// getters and setters here. No need for any #JsonGetter or #JsonSetter annotations
}
#JsonRootName("RecurringDetail")
public class RecurringDetailWrapper {
#JsonProperty("RecurringDetail")
RecurringDetail recurringDetail;
public RecurringDetail getRecurringDetail() {
return recurringDetail;
}
public void setRecurringDetail(RecurringDetail recurringDetail) {
this.recurringDetail = recurringDetail;
}
}
public class RecurringDetail implements java.io.Serializable {
private static final long serialVersionUID = 5302883242997268343L;
private String name;
private Date creationDate;
private Card card;
private AdditionalData additionalData;
private String socialSecurityNumber;
private String recurringDetailReference;
private String alias;
private String aliasType;
private String variant;
private String paymentMethodVariant;
private String firstPspReference;
private List<String> contractTypes;
private String acquirer;
private String acquirerAccount;
public class AdditionalData {
String cardBin;
public String getCardBin() {
return cardBin;
}
public void setCardBin(String cardBin) {
this.cardBin = cardBin;
}
}
// getters and setters here. No need for any #JsonGetter or #JsonSetter annotations
}
Then in your unit test:
#Test
public void testParseRecurringDetailResulte() throws IOException {
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("ID41901838.json");
ObjectReader objectReader = mapper.readerFor(RecurringDetailsResult.class);
RecurringDetailsResult result = objectReader.readValue(inputStream);
if (result.getDetails() != null && !result.getDetails().isEmpty()) {
RecurringDetailWrapper detail = result.getDetails().get(0);
if (StringUtils.isEmpty(detail.getRecurringDetail().getRecurringDetailReference())) {
fail("Recurring detail does not contain any information.");
}
} else {
fail("No result details returned.");
}
}
I posted the full working code here:
https://github.com/teacurran/java-experiments/tree/master/stackoverflow-sandbox/src/main/java/com/wirelust/stackoverflowsandbox/ID41901838
It seems your current structure will work for the response JSON as below (an extra named layer is removed)
{
"creationDate": "2017-01-26T23:11:20+01:00",
"details": [
{
"acquirer": "TestPmmAcquirer",
"acquirerAccount": "TestPmmAcquirerAccount",
"additionalData": {
"cardBin": "440000"
},
"alias": "B133243153928547",
"aliasType": "Default",
"card": {
"expiryMonth": "8",
"expiryYear": "2018",
"holderName": "Steve HAll",
"number": "0008"
},
"contractTypes": [
"RECURRING"
],
"creationDate": "2017-01-26T23:11:20+01:00",
"firstPspReference": "8524854686798738",
"paymentMethodVariant": "visadebit",
"recurringDetailReference": "8414854686802111",
"variant": "visa"
}
],
"invalidOneclickContracts": "false",
"lastKnownShopperEmail": "someones#email.com",
"shopperReference": "xggZcGauSSG5jP+akIlijQ=="
}
For named object maybe you can try something like
public class RecurringDetailsResult
implements java.io.Serializable {
private static final long serialVersionUID = 5297684963950973136L;
private Date creationDate;
private String shopperReference;
private List<Map<String,RecurringDetail>> details;
private String lastKnownShopperEmail;
#JsonGetter("creationDate")
public Date getCreationDate ( ) {
return this.creationDate;
}
#JsonSetter("creationDate")
public void setCreationDate (Date value) {
this.creationDate = value;
}
#JsonGetter("shopperReference")
public String getShopperReference ( ) {
return this.shopperReference;
}
#JsonSetter("shopperReference")
public void setShopperReference (String value) {
this.shopperReference = value;
}
#JsonGetter("details")
public List<Map<String, RecurringDetail>> getDetails ( ) {
return this.details;
}
#JsonSetter("details")
public void setDetails (List<Map<String, RecurringDetail>> value) {
this.details = value;
}
#JsonGetter("lastKnownShopperEmail")
public String getLastKnownShopperEmail ( ) {
return this.lastKnownShopperEmail;
}
#JsonSetter("lastKnownShopperEmail")
public void setLastKnownShopperEmail (String value) {
this.lastKnownShopperEmail = value;
}
}
I am trying to save an enum 'Status' into a custom class that implements parcelable. I have found online how I can save Strings, ints or enums in one class that implements parcelable, but not how I can save these three things all at once. I am sorry if the solution is obvious, but I just can't figure it out.
Here is what my enum looks like:
public enum Status {
INITIALIZED, UPDATED, DELETED
}
And this is what I have so far:
public class Recipe implements Parcelable{
private String id;//this should be an int, same problem
private String recipeName;
private String recipePreperation;
private Status status;
private final static int MAX_PREVIEW = 50;
public Recipe(int parId, String parRecipeName, String parRecipePreperation) {
this.id = "" + parId;
this.recipeName = parRecipeName;
this.recipePreperation = parRecipePreperation;
this.status = Status.INITIALIZED;
}
public Recipe(Parcel in){
String[] data = new String[4];
in.readStringArray(data);
this.id = data [0];
this.recipeName = data[1];
this.recipePreperation = data[2];
this.status = data[3];//what I intend to do, I know this is wrong
}
public int GetId() {
return Integer.parseInt(id);
}
public String GetRecipeName() {
return this.recipeName;
}
public void SetRecipeName(String parRecipeName) {
this.recipeName = parRecipeName;
}
public String GetRecipePreperation() {
return this.recipePreperation;
}
public void SetRecipePreperation(String parRecipePreperation) {
this.recipePreperation = parRecipePreperation;
}
public Status GetStatus() {
return this.status;
}
public void SetStatus(Status parStatus) {
this.status = parStatus;
}
public String toString() {
String recipe = this.recipeName + "\n" + this.recipePreperation;
String returnString;
int maxLength = MAX_PREVIEW;
if (recipe.length() > maxLength) {
returnString = recipe.substring(0, maxLength - 3) + "...";
} else {
returnString = recipe;
}
return returnString;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int arg1) {
dest.writeStringArray(new String [] {
this.id,
this.recipeName,
this.recipePreperation,
this.status//what I intend to do, I know this is wrong
});
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public Recipe createFromParcel(Parcel in) {
return new Recipe(in);
}
public Recipe[] newArray(int size) {
return new Recipe[size];
}
};
}
How do I save an int, an array of strings and an enum into a class that implements the parcelable, so it can writeToParcel()?
There's no need to read and write to/from string array. Just write each string and finally the status as Serializable. This is how I fix it.
public Recipe(Parcel in){
this.id = in.readString();
this.recipeName = in.readString();
this.recipePreperation = in.readString();
this.status = (Status) in.readSerializable();
}
public void writeToParcel(Parcel dest, int arg1) {
dest.writeString(this.id);
dest.writeString(this.recipeName);
dest.writeString(this.recipePreperation);
dest.writeSerializable(this.status);
}
This is my POJO class:
public class OrdineIngressi {
private Integer spettacolo;
private Integer settore;
private Integer pv;
private List<OrdineIngresso> ingressi=new ArrayList<OrdineIngresso>();
public OrdineIngressi(Integer spettacolo, Integer settore, Integer pv,
List<OrdineIngresso> ingressi) {
super();
this.spettacolo = spettacolo;
this.settore = settore;
this.pv = pv;
this.ingressi = ingressi;
}
public OrdineIngressi() {
super();
}
public Integer getSpettacolo() {
return spettacolo;
}
public void setSpettacolo(Integer spettacolo) {
this.spettacolo = spettacolo;
}
public Integer getSettore() {
return settore;
}
public void setSettore(Integer settore) {
this.settore = settore;
}
public Integer getPv() {
return pv;
}
public void setPv(Integer pv) {
this.pv = pv;
}
public List<OrdineIngresso> getIngressi() {
return ingressi;
}
public void setIngressi(List<OrdineIngresso> ingressi) {
this.ingressi = ingressi;
}
public class OrdineIngresso {
private Integer tipoingresso;
private Integer abbonamento;
private int numero;
private Integer[] posti;
public OrdineIngresso() {
super();
}
public OrdineIngresso(Integer tipoingresso, Integer abbonamento,
int numero, Integer[] posti) {
super();
this.tipoingresso = tipoingresso;
this.abbonamento = abbonamento;
this.numero = numero;
this.posti = posti;
}
public Integer getTipoingresso() {
return tipoingresso;
}
public void setTipoingresso(Integer tipoingresso) {
this.tipoingresso = tipoingresso;
}
public Integer getAbbonamento() {
return abbonamento;
}
public void setAbbonamento(Integer abbonamento) {
this.abbonamento = abbonamento;
}
public Integer[] getPosti() {
return posti;
}
public void setPosti(Integer[] posti) {
this.posti = posti;
}
public int getNumero() {
return numero;
}
public void setNumero(int numero) {
this.numero = numero;
}
}
}
This is the ajax input:
{"spettacolo":1,"settore":1,"pv":1,"ingressi":[{"tipoingresso":1,"abbonamento":null,"numero":1,"posti":[]}]}
When the Controller tries to unmarshal a json input I got this:
nested exception is org.codehaus.jackson.map.JsonMappingException: No suitable constructor found for type [simple type, class com.bean.OrdineIngressi$OrdineIngresso]: can not instantiate from JSON object (need to add/enable type information?)
Why? There is a default constructor!
You're almost there, you just need to make your inner class static:
...
public static class OrdineIngresso {
private Integer tipoingresso;
...
}
IIRC it has to do with the fact that a non-args inner class constructor really isn't non-args and thus jackson doesn't have a general manner for instantiating these non-static inner classes.
Cheers,