it-swarm-pt.tech

Erro de Jackson: nenhum construtor adequado

Estou usando Jackson para desserializar uma matriz json em alguns objetos. Aqui está a minha turma:

public class OfferContainer extends ActiveRecordBase{

    public Offer offer;

    public OfferContainer(){}

    public OfferContainer(Database db) {
        super(db);
    }

    @Override
    public String toString()
    {
        return this.getID() +  offer.toString();
    }

    public String getDescription() {
        return offer.description;
    }

    public String getBusinessName() {
        return offer.business.name;
    }



    public class Offer
    {
        public Category category;
        public String description;
        public String discount;
        public Date expiration;
        public Date published;
        public String rescinded_at;
        public String title;
        public String hook;
        public Date valid_from;
        public Date valid_to;
        public String id;
        public Business business;
        public Location location;
        public String image_270x155;

        public Offer() {
        }

        @Override
        public String toString()
        {
            return String.format(
                    "[Offer: category=%1$s, description=%2$s, discount=%3$s, expiration=%4$s, published=%5$s, rescinded_at=%6$s, title=%7$s, valid_from=%8$s, valid_to=%9$s, id=%10$s, business=%11$s, location=%12$s]",
                    category, description, discount, expiration, published, rescinded_at, title, valid_from, valid_to, id,
                    business, location);
        }

    }

   public enum Category
    {
        Salon, Spa, Restaurant, Other
    }

//    public class Category {
//        public String category;
//
//        public String toString() {
//            return String.format("[Category: category=%1$s]", category);
//        }
//    }


    public class Business
    {
        public String name;
        public String phone;
        public Address address;

        public Business(){}

        @Override
        public String toString()
        {
            return String.format(
                    "[Business: name=%1$s, phone=%2$s, address=%3$s]",
                    name, phone, address);
        }
    }


    public class Address
    {
        public String address_1;
        public String address_2;
        public String city;
        public String cross_streets;
        public String state;
        public String Zip;

        public Address() {
        }

        @Override
        public String toString()
        {
            return String.format(
                    "[Address: address_1=%1$s, address_2=%2$s, city=%3$s, cross_streets=%4$s, state=%5$s, Zip=%6$s]",
                    address_1, address_2, city, cross_streets, state, Zip);
        }
    }

    public class Location {
        public double latitude;
        public double longitude;

        public Location() {
        }

        public String toString() {
            return String.format("[Location: longitude=%1$s, latitude=%2$s]", longitude, latitude);
        }

    }

}

E o erro:

W/System.err(26911): org.codehaus.jackson.map.JsonMappingException: No suitable constructor found for type [simple type, class org.me.pojos.OfferContainer$Business]: can not instantiate from JSON object (need to add/enable type information?)
W/System.err(26911):  at [Source: [email protected]; line: 1, column: 382] (through reference chain: org.me.pojos.OfferContainer["offer"]->org.me.pojos.Offer["business"])
W/System.err(26911):    at org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromObjectUsingNonDefault(BeanDeserializer.Java:740)
W/System.err(26911):    at org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.Java:683)
W/System.err(26911):    at org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.Java:580)
W/System.err(26911):    at org.codehaus.jackson.map.deser.SettableBeanProperty.deserialize(SettableBeanProperty.Java:299)
W/System.err(26911):    at org.codehaus.jackson.map.deser.SettableBeanProperty$FieldProperty.deserializeAndSet(SettableBeanProperty.Java:579)
W/System.err(26911):    at org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.Java:635)
W/System.err(26911):    at org.codehaus.jackson.map.deser.SettableBeanProperty$InnerClassProperty.deserializeAndSet(SettableBeanProperty.Java:780)
W/System.err(26911):    at org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.Java:697)
W/System.err(26911):    at org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.Java:580)
W/System.err(26911):    at org.codehaus.jackson.map.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.Java:104)
W/System.err(26911):    at org.codehaus.jackson.map.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.Java:18)
W/System.err(26911):    at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.Java:2723)
W/System.err(26911):    at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.Java:1854)
W/System.err(26911):    at org.me.OffersUpdater.updateOffersIfNeeded(OffersUpdater.Java:107)
W/System.err(26911):    at com.activities.Main$UpdateOffersTask.doInBackground(Main.Java:265)
W/System.err(26911):    at com.activities.Main$UpdateOffersTask.doInBackground(Main.Java:239)
W/System.err(26911):    at Android.os.AsyncTask$2.call(AsyncTask.Java:185)
W/System.err(26911):    at Java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.Java:306)
W/System.err(26911):    at Java.util.concurrent.FutureTask.run(FutureTask.Java:138)
W/System.err(26911):    at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1088)
W/System.err(26911):    at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:581)
W/System.err(26911):    at Java.lang.Thread.run(Thread.Java:1019)

Eu estava usando o GSON, mas preciso abandoná-lo devido a problemas de desempenho. Quando mudei para Jackson, adicionei construtores padrão a todas as classes, o que provavelmente era desnecessário porque não havia outros construtores definidos ...

EDIT: Ah, e o JSON fica assim:

  [ { "offer" : { "business" : { "address" : { "address_1" : "340 9th Avenue",
                "address_2" : null,
                "city" : "New York",
                "cross_streets" : null,
                "state" : "NY",
                "Zip" : "10001"
              },
            "name" : "Blarney Stone",
            "phone" : "2125024656"
          },
        "category" : "Restaurant",
        "claim_link" : "http://m.thinknear.com/offers/BLARNEY__1323954754?app_id=kz4hjo&latitude=40.75042&longitude=-73.99633",
        "description" : "$1 off all drinks This discount was authorized by Toni Rossi. ",
        "discount" : null,
        "distance" : 161.40291744228713,
        "draws" : [ "American" ],
        "expiration" : "2011-12-15T21:59:59Z",
        "hook" : "$1 Off Drinks",
        "id" : "BLARNEY__1323954754",
        "image_270x155" : "https://s3.amazonaws.com/default_images/restaurant_stock_255x170.jpg",
        "location" : { "latitude" : "40.750444",
            "longitude" : "-73.99824579999999"
          },
        "mobile_claim_link" : "http://m.thinknear.com/offers/BLARNEY__1323954754?app_id=kz4hjo&latitude=40.75042&longitude=-73.99633",
        "published" : "2011-12-15T13:12:37Z",
        "rescinded_at" : null,
        "title" : "$1 Off All Drinks",
        "valid_from" : "2011-12-15T13:12:34Z",
        "valid_to" : "2011-12-15T21:29:59Z"
      } },
  { "offer" : { "business" : { "address" : { "address_1" : "252 W 31st St",
                "address_2" : null,
                "city" : "New York",
                "cross_streets" : null,
                "state" : "NY",
                "Zip" : "10019"
              },
            "name" : "Hush Spa for Men",
            "phone" : "2127570508"
          },
        "category" : "Spa",
        "claim_link" : "http://m.thinknear.com/offers/HUSH_SPA_1323962075?app_id=kz4hjo&latitude=40.75042&longitude=-73.99633",
        "description" : "Use this offer now to enjoy this great Spa at a 30% discount. Applies to all services except massages. This discount was authorized by Andy Paningua. ",
        "discount" : "30",
        "distance" : 185.37847063528784,
        "draws" : [ "Body Work",
            "Facial",
            "Hair Removal"
          ],
        "expiration" : "2011-12-16T02:59:59Z",
        "hook" : "30% OFF",
        "id" : "HUSH_SPA_1323962075",
        "image_270x155" : "https://s3.amazonaws.com/ThinkNearMobileImages/hush_255x170.jpg",
        "location" : { "latitude" : "40.7499612",
            "longitude" : "-73.9942143"
          },
        "mobile_claim_link" : "http://m.thinknear.com/offers/HUSH_SPA_1323962075?app_id=kz4hjo&latitude=40.75042&longitude=-73.99633",
        "published" : "2011-12-15T15:14:36Z",
        "rescinded_at" : null,
        "title" : "30% off at Hush Spa for Men",
        "valid_from" : "2011-12-15T15:14:35Z",
        "valid_to" : "2011-12-16T02:29:59Z"
      } },
  { "offer" : { "business" : { "address" : { "address_1" : "481 8th Ave",
                "address_2" : "Ste 740 ",
                "city" : "New York",
                "cross_streets" : "34th  & 35th (New Yorker Hotel)",
                "state" : "NY",
                "Zip" : "10001"
              },
            "name" : "Fusion Spa",
            "phone" : "+18325329272"
          },
        "category" : "Spa",
        "claim_link" : "http://m.thinknear.com/offers/FUSION_S_1323979416?app_id=kz4hjo&latitude=40.75042&longitude=-73.99633",
        "description" : "Use this offer now to enjoy this great Spa at a 20% discount. New customers only. Not valid with other offers. By appointment only. Call ahead for appointment. This discount was authorized by Tiffany Albert. ",
        "discount" : "20",
        "distance" : 350.0873566571568,
        "draws" : [ "Facial" ],
        "expiration" : "2011-12-16T01:59:59Z",
        "hook" : "20% OFF",
        "id" : "FUSION_S_1323979416",
        "image_270x155" : "https://s3.amazonaws.com/ThinkNearMobileImages/Fusion%2BSpa+1.jpg",
        "location" : { "latitude" : "40.7526135",
            "longitude" : "-73.99334859999999"
          },
        "mobile_claim_link" : "http://m.thinknear.com/offers/FUSION_S_1323979416?app_id=kz4hjo&latitude=40.75042&longitude=-73.99633",
        "published" : "2011-12-15T20:03:38Z",
        "rescinded_at" : null,
        "title" : "20% off at Fusion Spa",
        "valid_from" : "2011-12-15T20:03:36Z",
        "valid_to" : "2011-12-16T01:29:59Z"
      } }
]
20
LuxuryMode

Eu não trabalhei com Jackson, mas acho que o problema é que a classe Business é uma classe membro e não estática.

O que Jackson precisaria fazer é

new OfferContainer.Business()

Não pode fazer isso, pois é uma classe de membro. Tente tornar a classe estática.

public static class Business{ 
       ....
}
65
John Vint

Eu queria aceitar uma resposta que alguém postou antes, porque me levou na direção certa. Tornei cada classe de membro estática (e mais tarde tive que adicionar @JsonIgnoreProperties (ignoreUnknown = true) a uma delas) e funciona.

4
LuxuryMode