Swagger: How to annotate object mapped to string - java

I am using a custom ObjectMapper to map a class to a String for Json Serialization & Deserialization
module.addDeserializer(MonthUtil.class, new MonthUtilDeserializer());
module.addSerializer(MonthUtil.class, new MonthUtilSerializer());
Another class used by the REST API contains a field and getter of type MonthUtil. In the Swagger definition, that field gets class MonthUtil, although the serialized object contains a string.
How can I annotate the class, or if need be the field or getter to tell swagger that this is effectively a string?
I tried adding #ApiParam(type = "string") to the field and the getter, but that didn't help.
I would prefer to annotate the class as being represented by a string.

Related

Deserializing Java class with incomplete ParameterTyped properties - Jackson

Consider we are having the following classes
//following classes are present in external lib, we can not modify them.
class A{
private Map mapOfListOfB; // this should have been properly typed Map<String,List<B>>
}
class B{
private int val1;
private String val2;
private C val3; // Class C can be anything but the point here is the same object of C can be used in multiple B objects
//which means we can reuse the reference using #JsonIdentityInfo
}
now, when we use Jackson's objectMapper to serialize and deserialize this Class A,
we would not be able to deserialize because we are not giving any typed info to Jackson so it ends up creating List<LinkedHashMap>
here is one solution that I know, works for class having a collection with a specific class type
eg:
class D{
private Map mapOfB // which should have been Map<String,B>
}
// this can be typed by using jackson's mixin
abstract class DmixIn{
#JsonDeserialize(contentAs = B.class)
Map mapOfB
}
but how we can tell the type which is present in class A to Jackson as we can not pass ParameterizedType to contentAs, it just takes class instance.
I know we can write a custom deserializer to achieve the end result but I am looking for a more readable solution here, like any Jackson annotation or any simple config which we can be set on the property level.
and another issue(which can be because of my awareness) is I even need to maintain deserialization context while writing custom deserializers by using #JsonDeserialize(contentUsing = CustomDeserializer.class) because Class C references are reused and I may need to resolve IDs for this POJO while deserializing

Problems with sonar changing the names of an object in REST calls by Jackson JSON

I have an object that in its fields is mandatory that some names have '_' for example local_PC instead of localPC.
The problem I have is that I need it to be local_PC and when a call is made to my app they send that field and I can't change it, but sonar launches me error because it must be localPC
Is there any way I can control it by Jackson?
realizing #jsonproperty only allows me to change the names in the output but not in the input of the controller
#Data
#JsonInclude(JsonInclude.Include.NON_NULL)
#AllArgsConstructor
public class Example{
private String local_PC;
}
Use #JsonAlias
#JsonAlias is introduced in Jackson 2.9 release. #JsonAlias defines one or more alternative names for a property to be accepted during deserialization i.e. setting JSON data to Java object. But at the time of serialization i.e. while getting JSON from Java object, only actual logical property name is used and not alias. #JsonAlias
#JsonAlias({"local_PC", "localPC"})
private String local_PC;

Spring Boot serialize text/javascript to JSON

I created the following Kotlin data class:
#JsonInclude(JsonInclude.Include.NON_NULL)
public data class ITunesArtist(val artistName: String,
val artistId: Long, val artistLinkUrl: URL)
(a data class is a Kotlin class that auto-generates equals, hashcode, toString etc at compile time - saves time).
Now I've tried populating it using Spring RestTemplate:
#Test
fun loadArtist()
{
val restTemplate = RestTemplate()
val artist = restTemplate.getForObject(
"https://itunes.apple.com/search?term=howlin+wolf&entity=allArtist&limit=1", ITunesQueryResults::class.java);
println("Got artist: $artist")
}
It fails with:
Could not extract response: no suitable HttpMessageConverter found for response type
[class vampr.api.service.authorization.facebook.ITunesArtist]
and content type [text/javascript;charset=utf-8]
Fair enough - the JSON object mapper was probably expecting mime-type of text/json. Other than telling RestTemplate to map to String::class.java, and then instantiating an instance of JacksonObjectMapper by hand, is there a way to tell my RestTemplate to treat the returned mime type as JSON?
Instead of providing defaults for all properties in your data class you can also use this: https://github.com/FasterXML/jackson-module-kotlin
This Jackson module will allow you to serialize and deserialize Kotlin's data classes without having to worry about providing an empty constructor.
In a Spring Boot Application you can register the module with a #Configuration class like so:
#Configuration
class KotlinModuleConfiguration {
#Bean
fun kotlinModule(): KotlinModule {
return KotlinModule()
}
}
Other than that you can also use the extension functions mentioned in the documentation to register the module with Jackson.
Besides supporting data classes you will also get support for several classes from the Kotlin stdlib, like Pair for example.
Not sure about Spring, but Jackson needed me to specify that I worked with a Java Bean. You see, Kotlin data class is exactly the same as a standard Bean on the byte code level.
Do not forget that Java Bean specification implies an empty constructor (without parameters). A nice way to have it auto-generated is to provide default values for all parameters of your primary constructor.
To serialize an object from Jackson to String:
The 'get' portion of Java Beans specification is required.
To read a JSON string to object:
The 'set' portion of the spec is required.
Additionally the object requires an empty constructor.
Modify the class to include:
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonInclude(JsonInclude.Include.NON_NULL)
data public class ITunesArtist(var artistName: String? = null,
var artistId: Long = -1L, val amgArtistId: String = "id",
var artistLinkUrl: URL? = null)
Fields provide defaults in order for there to be an empty constructor.
Edit:
Uses the Kotlin Module from #mhlz's (now accepted) answer removes the need to provide a default constructor.

Jackson Deserialize To Concrete Class Based On Type

I have what I believe should be a simple use case.
I would like to serialize a POJO with type metadata (preferably a simple name I come up with, not the fully qualified class/package name), and later have Jackson deserialize the JSON back into the concrete class it came from by using this metadata. There is no inheritance hierarchy among classes being serialized and deserialized.
My scenario is I have a service which accepts multiple file types. For each file uploaded, the client can retrieve JSON data whose structure and type depends on the file it came from. Thus when I retrieve JSON from the service, it's not known what the concrete class is to deserialize to. I would like Jackson to figure this out based on metadata which it supplies.
For example, I'd like to be able to do this:
String json = ... // get JSON from the service
Object obj = mapper.readValue(json, Object.class) // concrete class is not known
System.out.println(obj.getClass()) // I want this to be MyConcreteClass.class
There is no inheritance hierarchy among JSON types returned.
I don't want to reveal package names or other internal service
details/structure.
I have control over Jackson's serialization process
Relevant question: Can jackson determine root object type to deserialize to when json includes type property?
Thank you so much for your help!
This can be achieved using Jackson's JavaType:
String className = "class.name.from.json.service";
JavaType dtoType = TypeFactory.defaultInstance().constructFromCanonical(className);
Object dto = new ObjectMapper().readValue(InputStream, dtoType);
assert dto.getClass().equals(dtoType.getRawClass());

Is there a way to modify a POJO field and return the POJO

Is there a way to modify the field of POJO with new property(like using MixIns or #JSONProperty) and get the modified POJO back ? (A way to add/modify field of a POJO dynamically ?)
Like I have a class
class PojoA<T>{
private T data;//field to be modified as NewData
}
So, I tried with MixIns like
public interface PojoMixIn<T> {
#JsonProperty("NewData")
T getData();
}
Now to get the modified field, I use ObjectMapper
mapper.addMixInAnnotations(PojoA.class,PojoMixIn.class);
mapper.writerWithDefaultPrettyPrinter().writeValueAsString(pojoA);
The actual result is a String, but can I be able to get the modified POJO?

Categories