001/*******************************************************************************
002 * Copyright 2017 The MIT Internet Trust Consortium
003 *
004 * Portions copyright 2011-2013 The MITRE Corporation
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 *******************************************************************************/
018package org.mitre.openid.connect.model;
019
020import java.io.IOException;
021import java.io.ObjectInputStream;
022import java.io.ObjectOutputStream;
023
024import javax.persistence.Basic;
025import javax.persistence.CascadeType;
026import javax.persistence.Column;
027import javax.persistence.Convert;
028import javax.persistence.Entity;
029import javax.persistence.GeneratedValue;
030import javax.persistence.GenerationType;
031import javax.persistence.Id;
032import javax.persistence.JoinColumn;
033import javax.persistence.NamedQueries;
034import javax.persistence.NamedQuery;
035import javax.persistence.OneToOne;
036import javax.persistence.Table;
037
038import org.mitre.openid.connect.model.convert.JsonObjectStringConverter;
039
040import com.google.gson.JsonObject;
041import com.google.gson.JsonParser;
042
043@Entity
044@Table(name="user_info")
045@NamedQueries({
046        @NamedQuery(name=DefaultUserInfo.QUERY_BY_USERNAME, query = "select u from DefaultUserInfo u WHERE u.preferredUsername = :" + DefaultUserInfo.PARAM_USERNAME),
047        @NamedQuery(name=DefaultUserInfo.QUERY_BY_EMAIL, query = "select u from DefaultUserInfo u WHERE u.email = :" + DefaultUserInfo.PARAM_EMAIL)
048})
049public class DefaultUserInfo implements UserInfo {
050
051        public static final String QUERY_BY_USERNAME = "DefaultUserInfo.getByUsername";
052        public static final String QUERY_BY_EMAIL = "DefaultUserInfo.getByEmailAddress";
053
054        public static final String PARAM_USERNAME = "username";
055        public static final String PARAM_EMAIL = "email";
056
057        private static final long serialVersionUID = 6078310513185681918L;
058
059        private Long id;
060        private String sub;
061        private String preferredUsername;
062        private String name;
063        private String givenName;
064        private String familyName;
065        private String middleName;
066        private String nickname;
067        private String profile;
068        private String picture;
069        private String website;
070        private String email;
071        private Boolean emailVerified;
072        private String gender;
073        private String zoneinfo;
074        private String locale;
075        private String phoneNumber;
076        private Boolean phoneNumberVerified;
077        private DefaultAddress address;
078        private String updatedTime;
079        private String birthdate;
080        private transient JsonObject src; // source JSON if this is loaded remotely
081
082
083        /**
084         * @return the id
085         */
086        @Id
087        @GeneratedValue(strategy=GenerationType.IDENTITY)
088        @Column(name = "id")
089        public Long getId() {
090                return id;
091        }
092        /**
093         * @param id the id to set
094         */
095        public void setId(Long id) {
096                this.id = id;
097        }
098        /* (non-Javadoc)
099         * @see org.mitre.openid.connect.model.UserInfo#getUserId()
100         */
101        @Override
102        @Basic
103        @Column(name="sub")
104        public String getSub() {
105                return sub;
106        }
107        /* (non-Javadoc)
108         * @see org.mitre.openid.connect.model.UserInfo#setUserId(java.lang.String)
109         */
110        @Override
111        public void setSub(String sub) {
112                this.sub = sub;
113        }
114        /* (non-Javadoc)
115         * @see org.mitre.openid.connect.model.UserInfo#getPreferredUsername
116         */
117        @Override
118        @Basic
119        @Column(name="preferred_username")
120        public String getPreferredUsername() {
121                return this.preferredUsername;
122        }
123        /* (non-Javadoc)
124         * @see org.mitre.openid.connect.model.UserInfo#setPreferredUsername(java.lang.String)
125         */
126        @Override
127        public void setPreferredUsername(String preferredUsername) {
128                this.preferredUsername = preferredUsername;
129        }
130        /* (non-Javadoc)
131         * @see org.mitre.openid.connect.model.UserInfo#getName()
132         */
133        @Override
134        @Basic
135        @Column(name = "name")
136        public String getName() {
137                return name;
138        }
139        /* (non-Javadoc)
140         * @see org.mitre.openid.connect.model.UserInfo#setName(java.lang.String)
141         */
142        @Override
143        public void setName(String name) {
144                this.name = name;
145        }
146        /* (non-Javadoc)
147         * @see org.mitre.openid.connect.model.UserInfo#getGivenName()
148         */
149        @Override
150        @Basic
151        @Column(name="given_name")
152        public String getGivenName() {
153                return givenName;
154        }
155        /* (non-Javadoc)
156         * @see org.mitre.openid.connect.model.UserInfo#setGivenName(java.lang.String)
157         */
158        @Override
159        public void setGivenName(String givenName) {
160                this.givenName = givenName;
161        }
162        /* (non-Javadoc)
163         * @see org.mitre.openid.connect.model.UserInfo#getFamilyName()
164         */
165        @Override
166        @Basic
167        @Column(name="family_name")
168        public String getFamilyName() {
169                return familyName;
170        }
171        /* (non-Javadoc)
172         * @see org.mitre.openid.connect.model.UserInfo#setFamilyName(java.lang.String)
173         */
174        @Override
175        public void setFamilyName(String familyName) {
176                this.familyName = familyName;
177        }
178        /* (non-Javadoc)
179         * @see org.mitre.openid.connect.model.UserInfo#getMiddleName()
180         */
181        @Override
182        @Basic
183        @Column(name="middle_name")
184        public String getMiddleName() {
185                return middleName;
186        }
187        /* (non-Javadoc)
188         * @see org.mitre.openid.connect.model.UserInfo#setMiddleName(java.lang.String)
189         */
190        @Override
191        public void setMiddleName(String middleName) {
192                this.middleName = middleName;
193        }
194        /* (non-Javadoc)
195         * @see org.mitre.openid.connect.model.UserInfo#getNickname()
196         */
197        @Override
198        @Basic
199        @Column(name = "nickname")
200        public String getNickname() {
201                return nickname;
202        }
203        /* (non-Javadoc)
204         * @see org.mitre.openid.connect.model.UserInfo#setNickname(java.lang.String)
205         */
206        @Override
207        public void setNickname(String nickname) {
208                this.nickname = nickname;
209        }
210        /* (non-Javadoc)
211         * @see org.mitre.openid.connect.model.UserInfo#getProfile()
212         */
213        @Override
214        @Basic
215        @Column(name = "profile")
216        public String getProfile() {
217                return profile;
218        }
219        /* (non-Javadoc)
220         * @see org.mitre.openid.connect.model.UserInfo#setProfile(java.lang.String)
221         */
222        @Override
223        public void setProfile(String profile) {
224                this.profile = profile;
225        }
226        /* (non-Javadoc)
227         * @see org.mitre.openid.connect.model.UserInfo#getPicture()
228         */
229        @Override
230        @Basic
231        @Column(name = "picture")
232        public String getPicture() {
233                return picture;
234        }
235        /* (non-Javadoc)
236         * @see org.mitre.openid.connect.model.UserInfo#setPicture(java.lang.String)
237         */
238        @Override
239        public void setPicture(String picture) {
240                this.picture = picture;
241        }
242        /* (non-Javadoc)
243         * @see org.mitre.openid.connect.model.UserInfo#getWebsite()
244         */
245        @Override
246        @Basic
247        @Column(name = "website")
248        public String getWebsite() {
249                return website;
250        }
251        /* (non-Javadoc)
252         * @see org.mitre.openid.connect.model.UserInfo#setWebsite(java.lang.String)
253         */
254        @Override
255        public void setWebsite(String website) {
256                this.website = website;
257        }
258        /* (non-Javadoc)
259         * @see org.mitre.openid.connect.model.UserInfo#getEmail()
260         */
261        @Override
262        @Basic
263        @Column(name = "email")
264        public String getEmail() {
265                return email;
266        }
267        /* (non-Javadoc)
268         * @see org.mitre.openid.connect.model.UserInfo#setEmail(java.lang.String)
269         */
270        @Override
271        public void setEmail(String email) {
272                this.email = email;
273        }
274        /* (non-Javadoc)
275         * @see org.mitre.openid.connect.model.UserInfo#getVerified()
276         */
277        @Override
278        @Basic
279        @Column(name="email_verified")
280        public Boolean getEmailVerified() {
281                return emailVerified;
282        }
283        /* (non-Javadoc)
284         * @see org.mitre.openid.connect.model.UserInfo#setVerified(java.lang.boolean)
285         */
286        @Override
287        public void setEmailVerified(Boolean emailVerified) {
288                this.emailVerified = emailVerified;
289        }
290        /* (non-Javadoc)
291         * @see org.mitre.openid.connect.model.UserInfo#getGender()
292         */
293        @Override
294        @Basic
295        @Column(name = "gender")
296        public String getGender() {
297                return gender;
298        }
299        /* (non-Javadoc)
300         * @see org.mitre.openid.connect.model.UserInfo#setGender(java.lang.String)
301         */
302        @Override
303        public void setGender(String gender) {
304                this.gender = gender;
305        }
306        /* (non-Javadoc)
307         * @see org.mitre.openid.connect.model.UserInfo#getZoneinfo()
308         */
309        @Override
310        @Basic
311        @Column(name="zone_info")
312        public String getZoneinfo() {
313                return zoneinfo;
314        }
315        /* (non-Javadoc)
316         * @see org.mitre.openid.connect.model.UserInfo#setZoneinfo(java.lang.String)
317         */
318        @Override
319        public void setZoneinfo(String zoneinfo) {
320                this.zoneinfo = zoneinfo;
321        }
322        /* (non-Javadoc)
323         * @see org.mitre.openid.connect.model.UserInfo#getLocale()
324         */
325        @Override
326        @Basic
327        @Column(name = "locale")
328        public String getLocale() {
329                return locale;
330        }
331        /* (non-Javadoc)
332         * @see org.mitre.openid.connect.model.UserInfo#setLocale(java.lang.String)
333         */
334        @Override
335        public void setLocale(String locale) {
336                this.locale = locale;
337        }
338        /* (non-Javadoc)
339         * @see org.mitre.openid.connect.model.UserInfo#getPhoneNumber()
340         */
341        @Override
342        @Basic
343        @Column(name="phone_number")
344        public String getPhoneNumber() {
345                return phoneNumber;
346        }
347        /* (non-Javadoc)
348         * @see org.mitre.openid.connect.model.UserInfo#setPhoneNumber(java.lang.String)
349         */
350        @Override
351        public void setPhoneNumber(String phoneNumber) {
352                this.phoneNumber = phoneNumber;
353        }
354        /* (non-Javadoc)
355         * @see org.mitre.openid.connect.model.UserInfo#getPhoneNumberVerified()
356         */
357        @Override
358        @Basic
359        @Column(name="phone_number_verified")
360        public Boolean getPhoneNumberVerified() {
361                return phoneNumberVerified;
362        }
363        /* (non-Javadoc)
364         * @see org.mitre.openid.connect.model.UserInfo#setPhoneNumberVerified(java.lang.Boolean)
365         */
366        @Override
367        public void setPhoneNumberVerified(Boolean phoneNumberVerified) {
368                this.phoneNumberVerified = phoneNumberVerified;
369        }
370        /* (non-Javadoc)
371         * @see org.mitre.openid.connect.model.UserInfo#getAddress()
372         */
373        @Override
374        @OneToOne(targetEntity = DefaultAddress.class, cascade = CascadeType.ALL)
375        @JoinColumn(name="address_id")
376        public Address getAddress() {
377                return address;
378        }
379        /* (non-Javadoc)
380         * @see org.mitre.openid.connect.model.UserInfo#setAddress(org.mitre.openid.connect.model.Address)
381         */
382        @Override
383        public void setAddress(Address address) {
384                if (address != null) {
385                        this.address = new DefaultAddress(address);
386                } else {
387                        this.address = null;
388                }
389        }
390        /* (non-Javadoc)
391         * @see org.mitre.openid.connect.model.UserInfo#getUpdatedTime()
392         */
393        @Override
394        @Basic
395        @Column(name="updated_time")
396        public String getUpdatedTime() {
397                return updatedTime;
398        }
399        /* (non-Javadoc)
400         * @see org.mitre.openid.connect.model.UserInfo#setUpdatedTime(java.lang.String)
401         */
402        @Override
403        public void setUpdatedTime(String updatedTime) {
404                this.updatedTime = updatedTime;
405        }
406
407        /**
408         * @return the birthdate
409         */
410        @Override
411        @Basic
412        @Column(name="birthdate")
413        public String getBirthdate() {
414                return birthdate;
415        }
416        /**
417         * @param birthdate the birthdate to set
418         */
419        @Override
420        public void setBirthdate(String birthdate) {
421                this.birthdate = birthdate;
422        }
423
424        @Override
425        public JsonObject toJson() {
426                if (src == null) {
427
428                        JsonObject obj = new JsonObject();
429
430                        obj.addProperty("sub", this.getSub());
431
432                        obj.addProperty("name", this.getName());
433                        obj.addProperty("preferred_username", this.getPreferredUsername());
434                        obj.addProperty("given_name", this.getGivenName());
435                        obj.addProperty("family_name", this.getFamilyName());
436                        obj.addProperty("middle_name", this.getMiddleName());
437                        obj.addProperty("nickname", this.getNickname());
438                        obj.addProperty("profile", this.getProfile());
439                        obj.addProperty("picture", this.getPicture());
440                        obj.addProperty("website", this.getWebsite());
441                        obj.addProperty("gender", this.getGender());
442                        obj.addProperty("zoneinfo", this.getZoneinfo());
443                        obj.addProperty("locale", this.getLocale());
444                        obj.addProperty("updated_at", this.getUpdatedTime());
445                        obj.addProperty("birthdate", this.getBirthdate());
446
447                        obj.addProperty("email", this.getEmail());
448                        obj.addProperty("email_verified", this.getEmailVerified());
449
450                        obj.addProperty("phone_number", this.getPhoneNumber());
451                        obj.addProperty("phone_number_verified", this.getPhoneNumberVerified());
452
453                        if (this.getAddress() != null) {
454
455                                JsonObject addr = new JsonObject();
456                                addr.addProperty("formatted", this.getAddress().getFormatted());
457                                addr.addProperty("street_address", this.getAddress().getStreetAddress());
458                                addr.addProperty("locality", this.getAddress().getLocality());
459                                addr.addProperty("region", this.getAddress().getRegion());
460                                addr.addProperty("postal_code", this.getAddress().getPostalCode());
461                                addr.addProperty("country", this.getAddress().getCountry());
462
463                                obj.add("address", addr);
464                        }
465
466                        return obj;
467                } else {
468                        return src;
469                }
470
471        }
472
473        /**
474         * Parse a JsonObject into a UserInfo.
475         * @param o
476         * @return
477         */
478        public static UserInfo fromJson(JsonObject obj) {
479                DefaultUserInfo ui = new DefaultUserInfo();
480                ui.setSource(obj);
481
482                ui.setSub(nullSafeGetString(obj, "sub"));
483
484                ui.setName(nullSafeGetString(obj, "name"));
485                ui.setPreferredUsername(nullSafeGetString(obj, "preferred_username"));
486                ui.setGivenName(nullSafeGetString(obj, "given_name"));
487                ui.setFamilyName(nullSafeGetString(obj, "family_name"));
488                ui.setMiddleName(nullSafeGetString(obj, "middle_name"));
489                ui.setNickname(nullSafeGetString(obj, "nickname"));
490                ui.setProfile(nullSafeGetString(obj, "profile"));
491                ui.setPicture(nullSafeGetString(obj, "picture"));
492                ui.setWebsite(nullSafeGetString(obj, "website"));
493                ui.setGender(nullSafeGetString(obj, "gender"));
494                ui.setZoneinfo(nullSafeGetString(obj, "zoneinfo"));
495                ui.setLocale(nullSafeGetString(obj, "locale"));
496                ui.setUpdatedTime(nullSafeGetString(obj, "updated_at"));
497                ui.setBirthdate(nullSafeGetString(obj, "birthdate"));
498
499                ui.setEmail(nullSafeGetString(obj, "email"));
500                ui.setEmailVerified(obj.has("email_verified") && obj.get("email_verified").isJsonPrimitive() ? obj.get("email_verified").getAsBoolean() : null);
501
502                ui.setPhoneNumber(nullSafeGetString(obj, "phone_number"));
503                ui.setPhoneNumberVerified(obj.has("phone_number_verified") && obj.get("phone_number_verified").isJsonPrimitive() ? obj.get("phone_number_verified").getAsBoolean() : null);
504
505                if (obj.has("address") && obj.get("address").isJsonObject()) {
506                        JsonObject addr = obj.get("address").getAsJsonObject();
507                        ui.setAddress(new DefaultAddress());
508
509                        ui.getAddress().setFormatted(nullSafeGetString(addr, "formatted"));
510                        ui.getAddress().setStreetAddress(nullSafeGetString(addr, "street_address"));
511                        ui.getAddress().setLocality(nullSafeGetString(addr, "locality"));
512                        ui.getAddress().setRegion(nullSafeGetString(addr, "region"));
513                        ui.getAddress().setPostalCode(nullSafeGetString(addr, "postal_code"));
514                        ui.getAddress().setCountry(nullSafeGetString(addr, "country"));
515
516                }
517
518
519                return ui;
520
521        }
522        /**
523         * @return the jsonString
524         */
525        @Override
526        @Basic
527        @Column(name = "src")
528        @Convert(converter = JsonObjectStringConverter.class)
529        public JsonObject getSource() {
530                return src;
531        }
532
533        /**
534         * @param jsonString the jsonString to set
535         */
536        public void setSource(JsonObject src) {
537                this.src = src;
538        }
539
540
541        private static String nullSafeGetString(JsonObject obj, String field) {
542                return obj.has(field) && obj.get(field).isJsonPrimitive() ? obj.get(field).getAsString() : null;
543        }
544
545        /* (non-Javadoc)
546         * @see java.lang.Object#hashCode()
547         */
548        @Override
549        public int hashCode() {
550                final int prime = 31;
551                int result = 1;
552                result = prime * result + ((address == null) ? 0 : address.hashCode());
553                result = prime * result + ((birthdate == null) ? 0 : birthdate.hashCode());
554                result = prime * result + ((email == null) ? 0 : email.hashCode());
555                result = prime * result + ((emailVerified == null) ? 0 : emailVerified.hashCode());
556                result = prime * result + ((familyName == null) ? 0 : familyName.hashCode());
557                result = prime * result + ((gender == null) ? 0 : gender.hashCode());
558                result = prime * result + ((givenName == null) ? 0 : givenName.hashCode());
559                result = prime * result + ((id == null) ? 0 : id.hashCode());
560                result = prime * result + ((locale == null) ? 0 : locale.hashCode());
561                result = prime * result + ((middleName == null) ? 0 : middleName.hashCode());
562                result = prime * result + ((name == null) ? 0 : name.hashCode());
563                result = prime * result + ((nickname == null) ? 0 : nickname.hashCode());
564                result = prime * result + ((phoneNumber == null) ? 0 : phoneNumber.hashCode());
565                result = prime * result + ((phoneNumberVerified == null) ? 0 : phoneNumberVerified.hashCode());
566                result = prime * result + ((picture == null) ? 0 : picture.hashCode());
567                result = prime * result + ((preferredUsername == null) ? 0 : preferredUsername.hashCode());
568                result = prime * result + ((profile == null) ? 0 : profile.hashCode());
569                result = prime * result + ((sub == null) ? 0 : sub.hashCode());
570                result = prime * result + ((updatedTime == null) ? 0 : updatedTime.hashCode());
571                result = prime * result + ((website == null) ? 0 : website.hashCode());
572                result = prime * result + ((zoneinfo == null) ? 0 : zoneinfo.hashCode());
573                return result;
574        }
575
576        /* (non-Javadoc)
577         * @see java.lang.Object#equals(java.lang.Object)
578         */
579        @Override
580        public boolean equals(Object obj) {
581                if (this == obj) {
582                        return true;
583                }
584                if (obj == null) {
585                        return false;
586                }
587                if (!(obj instanceof DefaultUserInfo)) {
588                        return false;
589                }
590                DefaultUserInfo other = (DefaultUserInfo) obj;
591                if (address == null) {
592                        if (other.address != null) {
593                                return false;
594                        }
595                } else if (!address.equals(other.address)) {
596                        return false;
597                }
598                if (birthdate == null) {
599                        if (other.birthdate != null) {
600                                return false;
601                        }
602                } else if (!birthdate.equals(other.birthdate)) {
603                        return false;
604                }
605                if (email == null) {
606                        if (other.email != null) {
607                                return false;
608                        }
609                } else if (!email.equals(other.email)) {
610                        return false;
611                }
612                if (emailVerified == null) {
613                        if (other.emailVerified != null) {
614                                return false;
615                        }
616                } else if (!emailVerified.equals(other.emailVerified)) {
617                        return false;
618                }
619                if (familyName == null) {
620                        if (other.familyName != null) {
621                                return false;
622                        }
623                } else if (!familyName.equals(other.familyName)) {
624                        return false;
625                }
626                if (gender == null) {
627                        if (other.gender != null) {
628                                return false;
629                        }
630                } else if (!gender.equals(other.gender)) {
631                        return false;
632                }
633                if (givenName == null) {
634                        if (other.givenName != null) {
635                                return false;
636                        }
637                } else if (!givenName.equals(other.givenName)) {
638                        return false;
639                }
640                if (id == null) {
641                        if (other.id != null) {
642                                return false;
643                        }
644                } else if (!id.equals(other.id)) {
645                        return false;
646                }
647                if (locale == null) {
648                        if (other.locale != null) {
649                                return false;
650                        }
651                } else if (!locale.equals(other.locale)) {
652                        return false;
653                }
654                if (middleName == null) {
655                        if (other.middleName != null) {
656                                return false;
657                        }
658                } else if (!middleName.equals(other.middleName)) {
659                        return false;
660                }
661                if (name == null) {
662                        if (other.name != null) {
663                                return false;
664                        }
665                } else if (!name.equals(other.name)) {
666                        return false;
667                }
668                if (nickname == null) {
669                        if (other.nickname != null) {
670                                return false;
671                        }
672                } else if (!nickname.equals(other.nickname)) {
673                        return false;
674                }
675                if (phoneNumber == null) {
676                        if (other.phoneNumber != null) {
677                                return false;
678                        }
679                } else if (!phoneNumber.equals(other.phoneNumber)) {
680                        return false;
681                }
682                if (phoneNumberVerified == null) {
683                        if (other.phoneNumberVerified != null) {
684                                return false;
685                        }
686                } else if (!phoneNumberVerified.equals(other.phoneNumberVerified)) {
687                        return false;
688                }
689                if (picture == null) {
690                        if (other.picture != null) {
691                                return false;
692                        }
693                } else if (!picture.equals(other.picture)) {
694                        return false;
695                }
696                if (preferredUsername == null) {
697                        if (other.preferredUsername != null) {
698                                return false;
699                        }
700                } else if (!preferredUsername.equals(other.preferredUsername)) {
701                        return false;
702                }
703                if (profile == null) {
704                        if (other.profile != null) {
705                                return false;
706                        }
707                } else if (!profile.equals(other.profile)) {
708                        return false;
709                }
710                if (sub == null) {
711                        if (other.sub != null) {
712                                return false;
713                        }
714                } else if (!sub.equals(other.sub)) {
715                        return false;
716                }
717                if (updatedTime == null) {
718                        if (other.updatedTime != null) {
719                                return false;
720                        }
721                } else if (!updatedTime.equals(other.updatedTime)) {
722                        return false;
723                }
724                if (website == null) {
725                        if (other.website != null) {
726                                return false;
727                        }
728                } else if (!website.equals(other.website)) {
729                        return false;
730                }
731                if (zoneinfo == null) {
732                        if (other.zoneinfo != null) {
733                                return false;
734                        }
735                } else if (!zoneinfo.equals(other.zoneinfo)) {
736                        return false;
737                }
738                return true;
739        }
740
741
742        /*
743         * Custom serialization to handle the JSON object
744         */
745        private void writeObject(ObjectOutputStream out) throws IOException {
746                out.defaultWriteObject();
747                if (src == null) {
748                        out.writeObject(null);
749                } else {
750                        out.writeObject(src.toString());
751                }
752        }
753        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
754                in.defaultReadObject();
755                Object o = in.readObject();
756                if (o != null) {
757                        JsonParser parser = new JsonParser();
758                        src = parser.parse((String)o).getAsJsonObject();
759                }
760        }
761
762}