I have interesting problem. Jackson overwrites values of properties on the 'parent' object with values of properties of 'child' object that have same name. So, to be more precise, this is Java structure I have
public class Contact {
...
String name;
List<Email> emails;
List<PhoneNumbers> phoneNumbers;
Account account;
...
}
public class Account {
...
String accountName;
List<Email> emails;
List<PhoneNumbers> phoneNumbers;
Account account;
...
}
So, when I form Contact JSON object and send it to server, everything goes fine until BeanDeserializer comes into account property of Contact class. Then, it starts reading proeprties of account part of JSON, which is ok, but does not create Account instance to set it on contact - it writes values of account's properties into properties with same names of Contact instance.
I am confused and not sure where to start looking how to fix this.
I'm not able to reproduce any problem similar to what's described in the original question.
The following example, created based on the descriptions in the original question, works as expected, without errors or improper deserialization.
import java.util.LinkedList;
import java.util.List;
import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.annotate.JsonCreator;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.ObjectMapper;
public class JacksonFoo
{
public static void main(String[] args) throws Exception
{
Account account1 = new Account();
account1.accountName = "account 1";
account1.emails = new LinkedList<Email>();
account1.emails.add(new Email("email_11#google.com"));
account1.emails.add(new Email("email_12#google.com"));
account1.phoneNumbers = new LinkedList<PhoneNumbers>();
account1.phoneNumbers.add(new PhoneNumbers(1111, 1112));
account1.phoneNumbers.add(new PhoneNumbers(1113, 1114));
Account account2 = new Account();
account2.accountName = "account 2";
account2.emails = new LinkedList<Email>();
account2.emails.add(new Email("email_21#google.com"));
account2.emails.add(new Email("email_22#google.com"));
account2.phoneNumbers = new LinkedList<PhoneNumbers>();
account2.phoneNumbers.add(new PhoneNumbers(2221, 2222));
account2.phoneNumbers.add(new PhoneNumbers(2223, 2224));
account2.account = account1;
Contact contact = new Contact();
contact.name = "contact";
contact.emails = new LinkedList<Email>();
contact.emails.add(new Email("email_31#google.com"));
contact.emails.add(new Email("email_32#google.com"));
contact.phoneNumbers = new LinkedList<PhoneNumbers>();
contact.phoneNumbers.add(new PhoneNumbers(3331, 3332));
contact.phoneNumbers.add(new PhoneNumbers(3333, 3334));
contact.account = account2;
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibilityChecker(
mapper.getVisibilityChecker()
.withFieldVisibility(Visibility.ANY));
String account1Json = mapper.writeValueAsString(account1);
String account2Json = mapper.writeValueAsString(account2);
String contactJson = mapper.writeValueAsString(contact);
System.out.println(account1Json); // {"accountName":"account 1","emails":[{"email":"email_11#google.com"},{"email":"email_12#google.com"}],"phoneNumbers":[{"phone1":1111,"phone2":1112},{"phone1":1113,"phone2":1114}],"account":null}
System.out.println(account2Json); // {"accountName":"account 2","emails":[{"email":"email_21#google.com"},{"email":"email_22#google.com"}],"phoneNumbers":[{"phone1":2221,"phone2":2222},{"phone1":2223,"phone2":2224}],"account":{"accountName":"account 1","emails":[{"email":"email_11#google.com"},{"email":"email_12#google.com"}],"phoneNumbers":[{"phone1":1111,"phone2":1112},{"phone1":1113,"phone2":1114}],"account":null}}
System.out.println(contactJson); // {"name":"contact","emails":[{"email":"email_31#google.com"},{"email":"email_32#google.com"}],"phoneNumbers":[{"phone1":3331,"phone2":3332},{"phone1":3333,"phone2":3334}],"account":{"accountName":"account 2","emails":[{"email":"email_21#google.com"},{"email":"email_22#google.com"}],"phoneNumbers":[{"phone1":2221,"phone2":2222},{"phone1":2223,"phone2":2224}],"account":{"accountName":"account 1","emails":[{"email":"email_11#google.com"},{"email":"email_12#google.com"}],"phoneNumbers":[{"phone1":1111,"phone2":1112},{"phone1":1113,"phone2":1114}],"account":null}}}
Account account1Copy = mapper.readValue(account1Json, Account.class);
Account account2Copy = mapper.readValue(account2Json, Account.class);
Contact contactCopy = mapper.readValue(contactJson, Contact.class);
System.out.println(account1.equals(account1Copy)); // true
System.out.println(account2.equals(account2Copy)); // true
System.out.println(contact.equals(contactCopy)); // true
}
}
class Contact
{
String name;
List<Email> emails;
List<PhoneNumbers> phoneNumbers;
Account account;
#Override
public boolean equals(Object o)
{
Contact c = (Contact) o;
if (name.equals(c.name))
if (emails.containsAll(c.emails))
if (c.emails.containsAll(emails))
if (phoneNumbers.containsAll(c.phoneNumbers))
if (c.phoneNumbers.containsAll(phoneNumbers))
return account.equals(c.account);
return false;
}
}
class Account
{
String accountName;
List<Email> emails;
List<PhoneNumbers> phoneNumbers;
Account account;
#Override
public boolean equals(Object o)
{
Account a = (Account) o;
if (accountName.equals(a.accountName))
if (emails.containsAll(a.emails))
if (a.emails.containsAll(emails))
if (phoneNumbers.containsAll(a.phoneNumbers))
if (a.phoneNumbers.containsAll(phoneNumbers))
if (account != null && a.account != null)
return account.equals(a.account);
else if (account == null && a.account == null)
return true;
return false;
}
}
class Email
{
String email;
#JsonCreator
Email(#JsonProperty("email") String e) {email = e;}
#Override
public boolean equals(Object o)
{
Email e = (Email) o;
return email.equals(e.email);
}
}
class PhoneNumbers
{
long phone1;
long phone2;
#JsonCreator
PhoneNumbers(#JsonProperty("phone1") long p1, #JsonProperty("phone2")long p2) {phone1 = p1; phone2 = p2;}
#Override
public boolean equals(Object o)
{
PhoneNumbers p = (PhoneNumbers) o;
return phone1 == p.phone1 && phone2 == p.phone2;
}
}
Related
In my below code, request is holding data {widgetName: "widgetName", widgetCriteria: "Activities", followUpDate: "1591727400000", uid: "someId"}
let request = JSON.parse(JSON.stringify(Object.assign(this.registrationForm.value, ...req)));
delete request.widgetFIlterOptions;
let uid = JSON.parse(window.localStorage.getItem("user")).uid;
request.uid = uid;
this.openWindow = false;
console.info("request-->", request);
this.contactService.addWidget(request).subscribe(res=> {
this.emService.updateWidgits();
})
Inside addWidget() function/method we are calling post request.
but after calling post request ResetController class should receive "followUpDate" with the other data. However in my case "followUpDate" is missing but I can see other data.
Can anyone help in this matter? What I am missing here? I am new to Angular.
addWidget(widget, data?) {
console.info("widget-->", widget); // here followUpDate is present
this.http.post(this.api.createWidget, widget).pipe(map(data => {
console.info("data-->", data); // this does not have the followUpDate.
let message = "Widget created successfully";
data['data'] = this.filterWidgets(data).length > 0 ? this.filterWidgets(data): alert("No data Available");
this.widgets.unshift(data);
this.toastr.success(message);
}),catchError(err => {
this.toastr.error(err.error);
return throwError(err);
}));
Below is my rest controller class
#RestController
public class DashboardController {
#Autowired
Service service;
#PostMapping(path = "createcriteria", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
#ApiOperation(value = "create the deal", response = Dashboard1.class)
public Dashboard1 saveCriteria(#RequestBody Dashboard1 dashboard1) {
System.out.println(dashboard1); // here "followUpDate" is missing
return service.saveCriteria(dashboard1);
}
}
Below is my Dashboard1 class
#Document(collection = "Dashboard1")
#JsonInclude(Include.NON_NULL)
public class Dashboard1 {
#Id
#ApiModelProperty(notes = "The database generated product ID")
private String id;
#Field(value = "widgetname")
private String WidgetName = null;
#Field(value = "widgetcriteria")
private String WidgetCriteria = null;
#Field(value = "uid")
private String uid = null;
#Field(value = "activitytype")
private String activityType = null;
#Field(value = "contactname")
private String contactName = null;
#Field(value = "updateby")
private String updateBy = null;
#Field(value = "followUpDate")
private String followUpDate = null;
// below all the getters, setters and toString() methods present
}
You dont need to JSON.stringfy the object. You just need to certify that the attribute names on json are the same of your class on spring, and just sed the pure object without the stringfy.
I found the issue in my code. Issue was in getters and setters. In my code field name and getter and setter name was different. Field name was followUpDate but the getter and setter name was getFallowUpDate() and setFallowUpDate(String)
I have three tables, one containing Cards, one containing CardDecks and third one implementing a many-to-many relation between the former two and additionally containg a symbol for every relation entry.
My task is to get three columns from the card-table and the symbol from the relation-table and save it in a data Object specifically designed for handling those inputs, the codition being, that all entries match the given deckId. Or in (hopefully correct) sql-language:
#Query("SELECT R.symbol, C.title, C.type, C.source " +
"FROM card_table C JOIN cards_to_card_deck R ON C.id = R.card_id"+
"WHERE R.card_deck_id = :cardDeckId")
LiveData<List<CardWithSymbol>> getCardsWithSymbolInCardDeckById(long cardDeckId);
But the room implementation class generates:
#Override
public LiveData<List<CardWithSymbol>> getCardsWithSymbolInCardDeckById(long
cardDeckId) {
final String _sql = "SELECT R.symbol, C.title, C.typ, C.source FROM
cards_to_card_deck R INNER JOIN card_table C ON R.card_id = C.id WHERE
R.card_deck_id = ?";
final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 1);
int _argIndex = 1;
_statement.bindLong(_argIndex, cardDeckId);
return new ComputableLiveData<List<CardWithSymbol>>() {
private Observer _observer;
#Override
protected List<CardWithSymbol> compute() {
if (_observer == null) {
_observer = new Observer("cards_to_card_deck","card_table") {
#Override
public void onInvalidated(#NonNull Set<String> tables) {
invalidate();
}
};
__db.getInvalidationTracker().addWeakObserver(_observer);
}
final Cursor _cursor = __db.query(_statement);
try {
final int _cursorIndexOfSymbol = _cursor.getColumnIndexOrThrow("symbol");
final List<CardWithSymbol> _result = new ArrayList<CardWithSymbol>(_cursor.getCount());
while(_cursor.moveToNext()) {
final CardWithSymbol _item;
final int _tmpSymbol;
_tmpSymbol = _cursor.getInt(_cursorIndexOfSymbol);
_item = new CardWithSymbol(_tmpSymbol,null,null,null);
_result.add(_item);
}
return _result;
} finally {
_cursor.close();
}
}
#Override
protected void finalize() {
_statement.release();
}
}.getLiveData();
}
Where
_item = new CardWithSymbol(_tmpSymbol,null,null,null);
should return my fully initialized object.
The CardWithSymbol class is declared as follows:
public class CardWithSymbol {
public int symbol;
public String cardName;
public String cardType;
public String cardSource;
public CardWithSymbol(int symbol, String cardName, String cardType, String cardSource){
this.symbol = symbol;
this.cardName = cardName;
this.cardType = cardType;
this.cardSource = cardSource;
}
And the types of the columns returned by the query are:
int symbol, String title, String type, String source
I already went through some debugging and the rest of the application works just fine. I can even read the symbol from the objects return by the query, but as mentioned above for some reason room ignores the other three parameters and just defaults them to null in the query-implementation.
So after some trial and error and reading through the dao-documentation once again i found my error:
When creating a class for handling subsets of columns in room, it is important to tell room which variable coresponds to which columns via #ColumnInfo(name = "name of the column goes here")-annotation.
So changing my CardWithSymbol class as follows solved the issue for me:
import android.arch.persistence.room.ColumnInfo;
public class CardWithSymbol {
#ColumnInfo(name = "symbol")
public int symbol;
#ColumnInfo(name = "title")
public String cardName;
#ColumnInfo(name = "type")
public String cardType;
#ColumnInfo(name = "source")
public String cardSource;
public CardWithSymbol(int symbol, String cardName, String cardType, String cardSource){
this.symbol = symbol;
this.cardName = cardName;
this.cardType = cardType;
this.cardSource = cardSource;
}
}
I've already successfully got the full name of a user using json:
#region get facebook name
//PUBLIC STATICS
public static string fbname;
private static string get_data;
public static string GetUserFBName()
{
FB.API("me?fields=name", Facebook.HttpMethod.GET, UserCallBack);
return fbname;
}
//USER CALLBACK
private static void UserCallBack(FBResult result)
{
if (result.Error != null)
{
get_data = result.Text;
}
else
{
get_data = result.Text;
}
var dict = Json.Deserialize(get_data) as IDictionary;
fbname = dict["name"].ToString();
}
#endregion
Now where do I begin with getting the email adress? I added the following to the permission:
FB.Login("email", AuthCallBack);
Thanks!
This question already has answers here:
BaseAdapter class wont setAdapter inside Asynctask - Android
(4 answers)
Closed 9 years ago.
I am trying to create my own arrayAdapter so I can place multiple textviews inside of a listview. I have searched everywhere and can not find a way to do it. I am new to this and not so sure how to handle it. So far I have an asynctask that gathers 3 strings in a JSON method. These strings are what I want placed in the textViews but I have no idea how to do so, here is my current code.
class loadComments extends AsyncTask<JSONObject, String, JSONObject> {
private ArrayAdapter<String> mAdapter = null;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
}
protected JSONObject doInBackground(JSONObject... params) {
JSONObject json2 = CollectComments.collectComments(usernameforcomments, offsetNumber);
return json2;
}
#Override
protected void onPostExecute(JSONObject json2) {
try {
if (json2.getString(KEY_SUCCESS) != null) {
registerErrorMsg.setText("");
String res2 = json2.getString(KEY_SUCCESS);
if(Integer.parseInt(res2) == 1){
JSONArray commentArray = json2.getJSONArray(KEY_COMMENT);
final String comments[] = new String[commentArray.length()];
for ( int i=0; i<commentArray.length(); i++ ) {
comments[i] = commentArray.getString(i);
}
JSONArray numberArray = json2.getJSONArray(KEY_NUMBER);
String numbers[] = new String[numberArray.length()];
for ( int i=0; i<numberArray.length(); i++ ) {
numbers[i] = numberArray.getString(i);
}
JSONArray usernameArray = json2.getJSONArray(KEY_USERNAME);
String usernames[] = new String[usernameArray.length()];
for ( int i=0; i<usernameArray.length(); i++ ) {
usernames[i] = usernameArray.getString(i);
}
ArrayList<String> myList = new ArrayList<String>();
class MyClassAdapter extends ArrayAdapter<String> {
private Context context;
public MyClassAdapter(Context context, int textViewResourceId, ArrayList<String> items) {
super(context, textViewResourceId, items);
this.context = context;
}
public View getView(int position, View convertView) {
View view = convertView;
if (view == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.list_item, null);
}
String item = getItem(position);
if (item!= null) {
// My layout has only one TextView
TextView commentView = (TextView) view.findViewById(R.id.listComment);
TextView usernameView = (TextView) view.findViewById(R.id.listPostedBy);
TextView NumberView = (TextView) view.findViewById(R.id.listNumber);
// do whatever you want with your string and long
commentView.setText(comments);
NumberView.setText(numbers);
usernameView.setText(usernames);
}
return view;
}
}
}//end if key is == 1
else{
// Error in registration
registerErrorMsg.setText(json2.getString(KEY_ERROR_MSG));
}//end else
}//end if
} //end try
catch (JSONException e) {
e.printStackTrace();
}//end catch
}
}
new loadComments().execute();
This code does not work but I think I am on the right track.
Let us say, you create a class that hold your information about the comments instead of creating three related Arrays :
class Commentary
{
public String username;
public String comment;
public int commentaryIndex;
}
The BaseAdapter can take a List as a parameter whereas the ArrayAdapter wouldn't.
class MyRealAdapter extends BaseAdapter
{
private List<Commentary> comments;
public MyRealAdapter(List<Commentary> comments )
{
this.comments = comments;
}
#Override
public int getCount() {
return comments.size();
}
#Override
public Object getItem(int index) {
return comments.get(index);
}
#Override
public long getItemId(int index) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Commentary c = (Commentary) getItem(position);
//c.username, c.comment, c.commentaryIndex
// create the view and stuff
return null;
}
}
As you can see, you again have the getView method but now you can retrieve your complete objet and not just a String.
There is a couple more method to override, but as you can see it's very simple.
You might need to pass other argument like a Context or a LayoutInflater to the constructor, but it's not mandatory.
EDIt :
JSONArray commentArray = json2.getJSONArray(KEY_COMMENT);
JSONArray numberArray = json2.getJSONArray(KEY_NUMBER);
JSONArray usernameArray = json2.getJSONArray(KEY_USERNAME);
ArrayList<Commentary> comments = new ArrayList<commentary>();
for ( int i=0; i<commentArray.length(); i++ ) {
Commentary c = new Commentary();
c.username = usernameArray.getString(i);
c.comment = commentArray.getString(i);
c.commentaryIndex = Integer.parseInt(numberArray.getString(i));
comments.add(c);
}
MyRealAdapter adapter = new MyRealAdapter(comments);
In my application I use method with account manager for getting owner emails. How I can test this method with Robolectric? Should I use for this purpose mocking? If I'm right, can I use Mockito? Is any tutorials how I can do it?
First I implemented the unit test
// Imports are skipped
/**
* Created by fminatchy on 25/02/14.
*/
#RunWith(RobolectricTestRunner.class)
#Config(manifest = "/src/main/AndroidManifest.xml")
public class TestAuthorization {
AccountManager accountManager;
Account account0;
Account account1;
Account account2;
#Before
public void init() {
creationComptes();
accountManager = AccountManager.get(Robolectric.application);
shadowOf(accountManager).addAccount(account0);
shadowOf(accountManager).addAccount(account1);
shadowOf(accountManager).addAccount(account2);
}
#Test
public void test_comptes() {
final AlbumsActivity activity = Robolectric.buildActivity(AlbumsActivity.class).create().get();
final String[] accountsName = activity.getGoogleAccounts();
assertThat(Arrays.asList(accountsName)).containsExactly("compte n°1", "compte n°3");
}
private void creationComptes() {
account0 = new Account("compte n°1", GoogleAccountManager.ACCOUNT_TYPE);
account1 = new Account("compte n°2", "pas google");
account2 = new Account("compte n°3", GoogleAccountManager.ACCOUNT_TYPE);
}
and their is the code located in the activity :
public String[] getGoogleAccounts() {
final AccountManager accountManager = AccountManager.get(this.getApplicationContext());
Account[] accounts = accountManager.getAccountsByType(GoogleAccountManager.ACCOUNT_TYPE);
String[] names = new String[accounts.length];
for (int i = 0; i < names.length; i++) {
names[i] = accounts[i].name;
}
return names;
}