I am using java w/ Jackson and would like to use a string prefix as my type for deserialization and the java pojo for generating that prefix at serialization.
class A implements TopLevel {
String id;
public String getPrefix() {
return "aPrefix"
}
}
class B implements TopLevel {
String id;
public String getPrefix() {
return "bPrefix"
}
}
interface TopLevel {
String getPrefix()
}
//This should create an instance of A w/ Id = "423412421421412RandomId"
mapper.readValue("aPrefix.423412421421412RandomId", TopLevel.class)
//This should create an instance of A w/ Id = "OtherRandomId"
B b = mapper.readValue("bPrefix.OtherRandomId", TopLevel.class)
//This should create string "bPrefix.OtherRandomId"
mapper.writeValue(b)
Ideally I would like to be able to define the following, and use #JsonSubTypes or the most standard Jackson way possible to be able to create these value type strings.
Related
i have the following method
public static <E> APIGatewayProxyResponseEvent generateResponse(E request, E response, int statusCode){
JSONObject result = new JSONObject();
result.put(Constants.REQUEST, request);
result.put(Constants.RESPONSE, response);
return new APIGatewayProxyResponseEvent()
.withBody(result.toString())
.withStatusCode(statusCode)
.withHeaders(Constants.commonHeaders);
}
i am getting net.sf.json.JSONException: java.lang.reflect.InvocationTargetException when result.put(Constants.RESPONSE, response); is executed
response is
Also the corresponding class is:
public class PhysicalMediaURL extends MediaURL {
private static final String IDENTIFIER_PREFIX = "images/I/";
public PhysicalMediaURL(String physicalId, String extension, MediaHostnameProvider mediaHostnameProvider) {
super("images/I/" + physicalId, extension, mediaHostnameProvider);
}
}
public abstract class MediaURL implements URL {
private final String identifier;
private final String extension;
private final MediaHostnameProvider mediaHostnameProvider;
public MediaURL(String identifier, String extension, MediaHostnameProvider mediaHostnameProvider) {
this.identifier = identifier;
this.extension = extension;
this.mediaHostnameProvider = mediaHostnameProvider;
}
public String getIdentifier() {
return this.identifier;
}
public String getExtension() {
return this.extension;
}
public String getDomainName() {
return this.mediaHostnameProvider.getMediaHostname(this.getExtension());
}
public String getURL() {
StringBuilder urlBuilder = new StringBuilder();
urlBuilder.append("https://");
urlBuilder.append(this.getDomainName());
urlBuilder.append('/');
urlBuilder.append(this.getIdentifier());
urlBuilder.append('.');
urlBuilder.append(this.getExtension());
return urlBuilder.toString();
}
public List<String> getStyleTags() {
return null;
}
}
where PhysicalMediaURL is of type: URL and that is an interface
public interface URL {
String getIdentifier();
String getDomainName();
String getExtension();
List<String> getStyleTags();
String getURL();
}
I am a bit stuck in this.. need help.
First off it looks like you are using a JSON implementation that is not updated as regularly as the other ones(Your exception is from net.sf.json). I always recommend using the org.json implementation as it receives regular updates and bugfixes.
Most implementations of JSONObject, when used in this form, use bean based reflection to retrieve values from your object. This is not always what you want when your object is in an inheritance hierarchy because, depending on the object and the JSONObject impl, it will pull fields from the implementation that are not on your higher level type(URL in this case).
If you really want a generic serialization function use something like Jackson or Gson that will allow you to specify the type as a part of the serialization. Otherwise consider transforming your objects, before they are passed to your generateResponse function, into simpler objects such as a Map<String, String> that can serialize unambiguously.
As a final thought JSONObject's generic serialization works, but, its performance is likely to be worse than using a dedicated higher level serializer like Jackson. It's best used with the explicit put methods to generate simple objects.
I'm using Spring boot Jackson dependency and lombok in my project, and in response i'm getting duplicate fields because of underscore
This is my model class:
#Getter
#Setter
#Accessors(chain = true)
#NoArgsConstructor
#ToString
public class TcinDpciMapDTO {
#JsonProperty(value = "tcin")
private String tcin;
#JsonProperty(value = "dpci")
private String dpci;
#JsonProperty(value = "is_primary_tcin_in_dpci_relation")
private boolean is_primaryTcin = true;
}
If i'm using underscore in is_primaryTcin field i'm getting below response with duplicate fields
{
"_primaryTcin": true,
"tcin": "12345",
"dpci": "12345",
"is_primary_tcin_in_dpci_relation": true
}
If i remove underscore from field isprimaryTcin then i'm getting correct response
{
"tcin": "12345",
"dpci": "12345",
"is_primary_tcin_in_dpci_relation": true
}
Is this because of underscore? but underscore is prefered to use in variable names right?
This is what your class look like after delomboking:
public class TcinDpciMapDTO {
#JsonProperty("tcin")
private String tcin;
#JsonProperty("dpci")
private String dpci;
#JsonProperty("is_primary_tcin_in_dpci_relation")
private boolean is_primaryTcin = true;
public String getTcin() {
return this.tcin;
}
public String getDpci() {
return this.dpci;
}
public boolean is_primaryTcin() {
return this.is_primaryTcin;
}
public TcinDpciMapDTO setTcin(String tcin) {
this.tcin = tcin;
return this;
}
public TcinDpciMapDTO setDpci(String dpci) {
this.dpci = dpci;
return this;
}
public TcinDpciMapDTO set_primaryTcin(boolean is_primaryTcin) {
this.is_primaryTcin = is_primaryTcin;
return this;
}
public TcinDpciMapDTO() {
}
public String toString() {
return "TcinDpciMapDTO(tcin=" + this.getTcin() + ", dpci=" + this.getDpci() + ", is_primaryTcin=" + this.is_primaryTcin() + ")";
}
}
If generated property name is not specified, Jackson generates it by stripping prefix is or get from the getter if using getter or by using Java field name if serializing field without using a getter. By default Jackson only uses getters during serialization. Because you put #JsonProperty on the fields, Jackson uses both fields and getters and checks if the field is already serialized by matching generated property name (this last part is my guess anyway) it does not recognize property generated from field is_primaryTcin and property generated from getter is_primaryTcin() as the same (one is internally named is_primaryTcin and the other _primaryTcin) - notice that if you rename is_primaryTcin to as_primaryTcin problem vanishes.
When you use is_primaryTcin that is not using underscore, it's using a mix of both.
You can fix it by using PropertyNamingStrategy.
If you do
...
#JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class)
public class TcinDpciMapDTO {
private String tcin;
private String dpci;
private boolean isPrimaryTcinInDpciRelation = true;
}
The JSON output will be
{
"tcin": "12345",
"dpci": "12345",
"is_primary_tcin_in_dpci_relation": true
}
I have a Java EE project that is using GSON library (Google's library for processing of JSON objects).
In my entity classes I use #Expose annotation to control which fields are considered by GSON. I also use serialize/deserialize properties on that annotation to control which fields are considered when serializing a Java object to JSON and which fields are considered when deserializing JSON objects to Java objects. For example:
public class Movie {
#Expose(serialize=true, deserialize=false)
#Id
#GeneratedValue
private long id;
#Expose(serialize=true, deserialize=true)
private String name;
#Expose(serialize=true, deserialize=true)
private String genre;
#Expose(serialize=false, deserialize=true)
private String secretID;
}
Here when I send the JSON object to be deserialized into Java object I send an object like this:
{
"name": "Memento",
"genre": "thriller",
"secretID": "123asd"
}
And, when I serialize Java object to JSON I get something like this:
{
"id": 1,
"name": "Memento",
"genre": "thriller"
}
I have this Java code:
public static void main(String[] args) {
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().setPrettyPrinting().create();
String json = gson.toJson(new Movie());
System.out.println(json);
}
that generates this as it's output:
{
"id": 0,
"name": "",
"genre": ""
}
Those are fields that are marked to be serialized. However, what if I need to print out all of the fields that are marked to be deserialized, so that I can easier create a JSON object that will be used as input when creating new Movies.
The desired output is this:
{
"name": "",
"genre": "",
"secretID": ""
}
Note: I don't want to change serialize/deserialize properties on #Expose annotations because they are set to how my application needs to work. I just need an easy way to generate a template JSON objects that will be used as input to my application, so I don't have to type it manually.
You could implement more generic ExclusionStrategy like:
#RequiredArgsConstructor
public class IncludeListedFields implements ExclusionStrategy {
#NonNull
private Set<String> fieldsToInclude;
#Override
public boolean shouldSkipField(FieldAttributes f) {
return ! fieldsToInclude.contains(f.getName());
}
#Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
}
then use it like:
Set<String> fieldsToInclude =
new HashSet<>(Arrays.asList("name", "genre", "secretID"));
ExclusionStrategy es = new IncludeListedFields(fieldsToInclude);
Gson gson = new GsonBuilder().setPrettyPrinting().serializeNulls()
.addSerializationExclusionStrategy(es).create();
Note following things:
You should not now use the builder method .excludeFieldsWithoutExposeAnnotation.
By default Gson does not serialize fileds with null values so you need to use builder method .serializeNulls(). This does not generate Json with string values "" but just null.
In your example Json fields contained empty strings as values but you did not introduce default constructor Movie() that would initialize field values to empty strings so they remain null. But if you initialize them - say to empty string ""- then they are not null & you do not need to use builder method .serializeNulls().
BUT if you really need and want only to serialize based on #Expose(deserialize=true) then the ExclusionStrategy can be just:
public class PrintDeserializeTrue implements ExclusionStrategy {
#Override
public boolean shouldSkipField(FieldAttributes f) {
Expose annotationExpose = f.getAnnotation(Expose.class);
if(null != annotationExpose) {
if(annotationExpose.deserialize())
return false;
}
return true;
}
#Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
}
I'm using camel(that uses jackson to parse) & parsing my pojos in json, but I'm getting output json:
{"com.xyz.Demo":{"key1":"val1","key2":"val2","fruits":
{"#serialization":"custom","unserializable-parents":"","list":{"default":
{"size":1},"int":1,"com.xyz.demo.Fruit":{"colour":"orange","timeStamp":"2020-
01-01T02:55:45Z"}}}}}
I want just class name, not with full package.
Also don't want: "#serialization":"custom","unserializable-parents":""
Respective classes:
public class Demo {
private String key1 = null;
private String key2 = null;
private Fruits fruits = null;
}
public class Fruits extends ArrayList<Fruit> {
}
public class Fruit {
private String colour = null;
private String timeStamp = null;
}
Conversion in Camel route: .marshal().json()
Tried annotating model classes with #JsonRootName , didn't work.
I have 2 classes
public class A {
protected String id;
}
And
public class B extends A {
private String bval;
}
The JSON we recieve for class B has the id with a different name, is there are way to tell jackson to use a different property name for id in classB than in classA?
Obe way to do it is to use the "any setter" feature, where Jackson is told to call a method for all "unknown" properties. You can then do the assignment yourself:
public class B extends A {
// all unknown properties will go here
#JsonAnySetter
public void setUnknownProperty(String key, Object value) {
if (key.equals("anotherNameForId")) {
id = (String)value;
}
}
I was using lombok
#Getter(onMethod = #__( #JsonProperty("id")))
and in class B
#Override
#JsonProperty("bID")
public String getId(){
return this.id;
}