I'm working on an android application using robospice, spring and jackson. Everything works fine except that cache results don't have relations of POJO classes.
For instance;
public class User extends SampleBase {
public int id;
public String name;
public Address address;
}
public class Address extends SampleBase {
public int id;
public String street;
public String city;
}
public class SampleBase {
// Base class of all POJO classes
}
When I send a request to get a user, I get all the values properly. However, when I try to get a user from cache, the address field returns null. If there's a relation between two classes, those relation fields are null but other fields are OK.
The result of request:
User:
id: 1
name: "Test User"
address: Address Object
The result of cache:
User:
id: 1
name: "Test User"
address: null
In my design, all of the POJO classes extend SampleBase. And there is only one RequestListener:
public class SampleRequestListener implements RequestListener<SampleBase> {
#Override
public void onRequestSuccess(SampleBase result) {
// Some operations
}
#Override
public void onRequestFailure(SpiceException e) {
// Some operations
}
}
I don't know if it's about my request listener but this works fine while sending requests. Is there something else that I should do to get the related objects of a cached object?
It is strange, we often do this and it works fine. Try to find some solution on jackson forum, RS is just a wrapper here.
Related
I want to get information from baidu music web api. I use below tow link:
http://openapi.baidu.com/rest/2.0/music/billboard/billlist?page_size=50×tamp=2016-09-22+18%3A47%3A54&sign=b2e34bd4b6c19a065d5a7e49e591a41b&session_key=9mzdDcHtDENrxP3Spvk7ZFbNHNijT8l8fN%2BfI%2Fe3U5rh3U5g%2FDVvjZyqB48aJaYO5qaqw4JbugF79hgAQ%2FGBIixUSuaP&type=21&page_no=1
http://openapi.baidu.com/rest/2.0/music/billboard/billlist?page_size=50×tamp=2016-09-26+17%3A42%3A18&sign=62cc904c8ff2817280f699a4bd4b6496&session_key=9mzdDcHtDENrxP3Spvk7ZFbNHNijT8l8fN%2BfI%2Fe3U5rh3U5g%2FDVvjZyqB48aJaYO5qaqw4JbugF79hgAQ%2FGBIixUSuaP&type=23&page_no=1
only type is different. one is 23 and another is 21. For return jason: one is billboard21, another is billboard23. If I want to use retrofit2 to accessa api and parse return jason, should I define two different java class to handler this two different return? In face, there is about 17 type, how can I handle this case if don't want to create 17 java classes?
my access api is:
#GET("/rest/2.0/music/billboard/billlist")
Call<BaiduBillListContainer> getBillList(#Query("timestamp") String timestamp,
#Query("type") String type,
#Query("sign") String sign,
#Query("session_key") String sessionkey,
#Query("page_size") String pagesize,
#Query("page_no") String pageno);
BaiduBillListContainer.java define:
public class BaiduBillListContainer implements Serializable {
BaiduBillList billboard21;
public BaiduBillList getBillBoardInfo() {
return billboard21;
}
public void setBillBoardInfo(BaiduBillList billBoardInfo) {
this.billboard21 = billBoardInfo;
}
}
it cannot used to get billboard23 return. Any one can help me about this question? thanks very much.
Try this:
public class BaiduBillListContainer implements Serializable {
Map<String,BaiduBillList> billboard;
public Map<String,BaiduBillList> getBillBoardInfo() {
return billboard;
}
public void setBillBoardInfo(Map<String,BaiduBillList> billBoardInfo) {
this.billboard= billBoardInfo;
}
}
Then call billboard from map like:
Map<String,BaiduBillList> getBBData=response.body();
BaiduBillList receivedBBList=getBBData.values().toArray()[0]
I have a class Shop
public class Shop {
private String name;
private ArrayList<Fruitable> fruits;
public String toJson() {
Gson gson = new Gson();
return gson.toJson(this, Shop.class)
}
}
Apple and Orange are the two classes that implements Fruitable interface.
Fruitable:
public interface Fruitable {
String getColor();
}
Apple:
public class Apple implements Fruitable {
private int Id;
#Override
public String getColor() {
return "red";
}
}
Orange:
public class Orange implements Fruitable {
private int Id;
#Override
public String getColor() {
return "orange";
}
}
I can serialize Shop using GSON, however, I cannot deserialize it properly.
When I deserialize, the ArrayList<Fruitable> has objects, but the objects are null.
This is because GSON requires a concrete instance to deserialze into.
I know I can implement JsonDeserializer in Shop.
However, can I implement some deserializing mechanism, inside Apple and Orange so they will deserialize themselves?
If that is not possible, and I have to write a deserializer in Shop, can I write code just to deserialize the fruits property and not the other properties,i.e. GSON will deserialize the remaining properties assuming they are concrete instances?
Ok so you should use GSON annotations they will make your life a whole lot easier.
An example:
public class Deal{
#SerializedName("name")
String name;
#SerializedName("times")
List<DealTime> times;
}
The json coming back will roughly look this:
{
name:dave,
times[
{
end:400,
start:200
},
{
end:30,
start:500
}
]
}
Then your DealTime class will have the following:
public class DealTime{
#SerializedName("end")
int end;
#SerializedName("start")
int start;
}
All you have to do is cast the json coming back with GSON using the Deal object.
Hope this helps.
I'm using GreenDao to handle my Dao on Android. GreenDao uses a Java Application to generate all Dao classes automatically. As such, you don't want to modify the classes as your custom code will be overwritten on the next run of the Java App.
This is my current approach to separation, it seems close, but very redundant:
Dao Model (automatically generated):
public class Car() {
...
String mMake;
String mModel;
int mMilesDriven;
...
public String getMake() {
return mMake;
}
public String getModel() {
return mModel;
}
public int getMilesDriven() {
return mMilesDriven;
}
}
Business Logic Class:
public class CarUtil() {
Car mCar;
public CarUtil(Car car) {
mCar = car;
}
public String getName() {
return mCar.getMake() + " " + mCar.getModel();
}
public int getMilesDriven() {
return mCar.getMilesDriven();
}
}
Obviously this looks horribly redundant, however, since Car() is auto generated and can't have the correct business logic (such as combining the make and model for the car's name), I think it's necessary redundancy?
I believe my models achieve good abstraction of the data layer and the business logic layer, but how can I make it more efficient as in less code?
Thank you!
You can put your business logic into the KEEP-SECTION-blocks. These won't get overwritten. (You have to tell the greendao generator to use KEEP-SECTIONS.)
If you don't want to expose some generated publicmethods you can also have an interface on your generated class which only exposes the things you want and work with that interface in your application.
UPDATE
Interface:
public interface CarUtil {
String getName();
int getMilesDriven();
}
Entity (generated);
public class Car() implements CarUtil {
...
String mMake;
String mModel;
int mMilesDriven;
...
public String getMake() {
return mMake;
}
public String getModel() {
return mModel;
}
public int getMilesDriven() {
return mMilesDriven;
}
// KEEP-SECTION-START
#Override
public String getName() {
return getMake() + " " + getModel();
}
}
So normally you just use the interface and so the interface and so the other public methods are hidden.
Depending on your needs it might be best to wrap the generated DAO (not the entity) so that only the DAO-layer knows about the real implementation.
I have the following Object and i want to use RxJava in order to create a new object. The logic behind this is that each article has a lot of comments. And it finds the correct comments using the ArticleData.commentId and the Comment.id.
public class ArticlesResponse {
public List<ArticleData> articles;
public List<Data> comments;
}
public class Data {
public int id;
public String link;
public String title;
public String author
public String body;
}
public class ArticleData extends Data {
public List<int> commentId;
}
So how can i use Rxjava in order to create the following object
public class Article extends Data {
public List<Comments> comments;
}
public class Comments extends Data {
// comments will have more attributes in the feature
// so use a seperate object
}
I know that i have to use the flapMap and the filter in order to parse the "ArticleResponse" but i don't know how to put all this together.
Furthermore the "ArticleResponse" is being generated from a json which i got from Retrofit, so i guess it will be better to use RxJava since i already have the Observable instead of putting nested for's inside my Callback.
I assume you means that articlesResponse.comments is a list contains all Comments of these all ArticleData, although I don't think wrap these data together and do the map operation in client is a good idea, this job should be done at server.
And I think maybe your ArticlesResponse's comments field should be a List<Comments>.
With these assumption, the code below may do the job you want (I put them in a TempTest class, and define an interface you described, and mock it to pass javac compile, and I also use Java 8 lambda grammar for code simplicity).
public class TempTest {
public static class Data {
public int id;
public String link;
public String title;
public String author;
public String body;
}
public static class ArticleData extends Data {
public List<Integer> commentId;
}
public static class Comments extends Data {
// comments will have more attributes in the feature
// so use a seperate object
}
public static class ArticlesResponse {
public List<ArticleData> articles;
public List<Comments> comments;
}
public class Article extends Data {
public List<Comments> comments;
}
public interface TestInterface {
Observable<ArticlesResponse> getArticle();
}
public static Comments findCommentWithId(int commentId, List<Comments> comments) {
for (Comments comment : comments) {
if (comment.id == commentId) {
return comment;
}
}
return null;
}
#Test
public void simpleTestcase() {
// assume you means that articlesResponse.comments is a list contains all Comments of these
// all ArticleData, although I don't think wrap these data together and do the map operation
// in client is a good idea, this job should be done at server
TestInterface testInterface = mock(TestInterface.class);
testInterface.getArticle().map(articlesResponse -> {
List<Article> result = new ArrayList<>();
// for each ArticleData in articlesResponse.articles
for (ArticleData articleData : articlesResponse.articles) {
// get all Comments from articlesResponse.comments
Article article = new Article();
// ... copy Data field from articleData to article
article.comments = new ArrayList<>();
for (Integer id : articleData.commentId) {
Comments comment = findCommentWithId(id, articlesResponse.comments);
if (comment != null) {
article.comments.add(comment);
}
}
result.add(article);
}
return result;
}).subscribe(articles -> {
for (Article article : articles) {
System.out.println(article);
}
});
}
}
Kind of confused at what your actual question is, so hopefully this helps. Retrofit can return an Observable for you, which should make RxJava integration easy. For example, in your service you could make:
#GET(<your endpoint>)
Observable<ArticlesResponse> getArticles();
And call it like:
<yourService>.getArticles()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedules.mainThread())
.subscribe() // manipulate how you want
I started using Retrofit recently. I don't know much about it. I have googled this issue and no answers suite my problem.
This is JSON response
{
"results": [
{
"description_eng": "This is second time testing",
"img_url": "-",
"title_eng": "Second test"
},
{
"description_eng": "Hello 1 2 3, I am testing.",
"img_url": "https://fbcdn-sphotos-f-a.akamaihd.net/hphotos-ak-xpa1/t31.0-8/s720x720/10838273_816509855058935_6428556113200361121_o.jpg",
"title_eng": "Test"
}
]
}
This is Feed Class
public class Feed {
public List<Results> results;
class Results{
String description_eng,img_url,title_eng;
}
}
This is the interface
public interface GetApi {
#GET("/api.json")
public void getData(Callback<List<Feed>> response);
}
I got json_illegal_syntax Exception.
This is how I solved this problem, by creating empty constructors.
Feed.class
public class Feed{
private List<Result> results;
public Feed(){}
public List<Result> getFeed(){
return this.results;
}
public void setFeed(List<Result> results) {
this.results = results;
}
}
Result.class
public class Result{
private String description_eng;
private String img_url;
private String title_eng;
public Result(){}
//getters and setters
}
GetApi.class
public interface GetApi {
#GET("/api.json")
public void getData(Callback<Feed> response);
}
Retrofit uses Gson by default to convert HTTP bodies to and from JSON. If you want to specify behavior that is different from Gson's defaults (e.g. naming policies, date formats, custom types), provide a new Gson instance with your desired behavior when building a RestAdapter.
Gson can not automatically deserialize the pure inner classes since their no-args constructor also need a reference to the containing Object which is not available at the time of deserialization. You can address this problem by either making the inner class static or by providing a custom InstanceCreator for it. Here is an example:
public class A {
public String a;
class B {
public String b;
public B() {
// No args constructor for B
}
}
}
NOTE: The above class B can not (by default) be serialized with Gson.
You should read more about GSON library
#Ye Min Htut Actually, even better is to write Feed class with generics.
public class FeedList<T>{
private List<T> feeds;
public Feed() {
}
public List<T> getFeed(){
return this.feeds;
}
public void setFeed(List<T> results) {
this.feeds = feeds;
}
}
and if there is something similar with only one object, than you can remove List part and get/set single object.
Now you can call FeedList<Result> or with whatever object you want.
GetApi.class
public interface GetApi {
#GET("/api.json")
public void getData(Callback<FeedList<Result>> response);
}
#Ye Min Htut I will suggest you to make Model/POJO classes using ROBOPOJO Generator It will generate All model classes for you, you don't need to make it by your self, Will also help you in future while creating model class. It just need JSON string and click will make your job done