0

I have an embedded entity that has a Field of type Map<String, Object>.

All keys to the Map Are of type String.

Below is Entity

@Entity
@Index
@Getter @Setter
public class NiftySurveys {
    @Id
    private Long id;
    private List<SurveyQuestions> questions;
    private Long createddate;
    private Long updatedDate;
}

@Getter @Setter
public class SurveyQuestions {
    private String label;
    private String code;
    private SurveyQuestionGroups questionGroup;
    private Map<String,Object> optionGroup;
}

I am having trouble saving Entity with optionGroup.

Sample Entity submitted From FrontEnd

{
    "questions": [{
        "label": "jio",
        "code": null,
        "questionGroup": {
            "name": "Date Time",
            "value": "DATI"
        },
        "optionGroup": {
            "labels": [{
                "label": "Date / Time"
            }],
            "collectDateInfo": true,
            "collectTimeInfo": true,
            "dateFormat": "MM/DD/YYYY",
            "validationMessage": "Please Enter a Valid Date!"
        }
    }, {
        "code": null,
        "label": "Q2",
        "questionGroup": {
            "name": "Multiple Choice Questions",
            "value": "MCQ"
        },
        "optionGroup": {
            "name": "Agree - Disagree",
            "code": "AGDAG",
            "options": [{
                "label": "YES",
                "value": "Y"
            }, {
                "label": "NO",
                "value": "N"
            }]
        }
    }]
}

All Keys of the map Are Strings.

Error Message:

exception: "com.googlecode.objectify.SaveException"
message: "Error saving com.nifty.niftyfeedbacks.domain.NiftySurveys@4ac88d5e: java.lang.IllegalStateException: Embedded Map keys must be of type String/Enum/Key<?> or field must specify @Stringify"

link to Stack Trace https://drive.google.com/file/d/1fqpPLiJutWLif5GnrlqLEZ6Wr_PdLdC-/view?usp=sharing

lufy
  • 43
  • 9
  • This looks like it should be fine. What's the full stacktrace? Generally it's better to model object graphs without java serialization, if you can get away with it. You'll have trouble reading @Serialized data from python or some other language in the future. – stickfigure Aug 10 '20 at 17:56
  • I have updated the question and added a full stack trace. – lufy Aug 11 '20 at 07:40
  • Looks like the inner map inside the list inside the map is causing the problem. You didn't mention if this is v5 or v6; if v6, it *might* with v6, I'm not sure. There are significant limits to what Objectify can do with `Object`, the type of your upper map value. @Serialize is the right answer. Or if you want something more portable, you could make the native field a private String and serialize/deserialize it to JSON in lifecycle methods. – stickfigure Aug 11 '20 at 14:30

2 Answers2

1

To see how @Stringify works, look at https://github.com/objectify/objectify/wiki/Entities#stringify :

In order to use non-String keys with Maps, you may specify the @Stringify annotation:

import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Stringify;
import com.googlecode.objectify.stringifier.Stringifier;

class DateStringifier implements Stringifier<LocalDate> {
    @Override
    public String toString(LocalDate obj) {
        return obj.getString();
    }

    @Override
    public LocalDate fromString(String str) {
        return new LocalDate(str);
    }
}

@Entity
class Car {
    @Id Long id;
    @Stringify(DateStringifier.class)
    Map<LocalDate, ServiceRecord> serviceHistory = new HashMap<>();
}

Previous response : The error message is clear : you must provide a "String-way" to handle your embedded entity. So you should write a toString() method inside your embedded entity or use the @Stringify annotation as appropriate.

It seems to be JSON, so did you try to use @JsonUnwrapped : @see https://stackoverflow.com/a/10077262/390462

class Item {
    private String title;

    @JsonProperty("date")
    private Date createdAt;

    // How to map this?
    @JsonUnwrapped
    private Author author;
}

You can go through a good JPA tutorial to handle Embedded objects too :

  1. https://examples.javacodegeeks.com/enterprise-java/jpa/jpa-embedded-embeddable-example/
  2. https://www.logicbig.com/tutorials/java-ee-tutorial/jpa/embeddable-classes.html
  3. https://www.tutorialspoint.com/ejb/ejb_embeddable_objects.htm
BendaThierry.com
  • 2,080
  • 1
  • 15
  • 17
  • I have used ```@stringify``` but it didn't work. it fails at nested Map i,e labels in first array and options in second array which has nested maps. – lufy Aug 10 '20 at 12:55
  • Did you try with @JsonUnwrapped ? Is it working as you want to ? – BendaThierry.com Aug 10 '20 at 13:02
  • @Jsonunwrapped is not required I need to save questions with Key called question and the error is specific to >>Objectify – lufy Aug 10 '20 at 13:28
  • Then read that : https://github.com/objectify/objectify/wiki/Entities. Response updated. – BendaThierry.com Aug 10 '20 at 13:33
  • All my Keys are Strings ```labels,collectDateInfo,collectTimeInfo,validationMessage,dateFormat``` from first optionGroup and ```name,options,code``` from Second OptionGroup – lufy Aug 10 '20 at 13:48
  • But you are putting them inside an embedded class, which is not a String. You must tell how serialize it or it will not work. – BendaThierry.com Aug 10 '20 at 13:49
  • Thanks, @ThierryB for the suggestion to look into docs. – lufy Aug 10 '20 at 14:21
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/219548/discussion-between-lufy-and-thierryb). – lufy Aug 10 '20 at 14:42
0

Use @Serialize annotation for complex object graph. From Objectify Docs

This Solved my issue.

@Getter @Setter
public class SurveyQuestions implements Serializable{
    private static final long serialVersionUID = -6930992373082651231L;
    @Serialize
    private Map<String,Object> optionGroup;
    
    
}
lufy
  • 43
  • 9