How to consume Page<Entity> response using Spring RestTemplate - java

I'm using spring data (mongoDb) and I've got my repository:
public interface StoriesRepository extends PagingAndSortingRepository<Story, String> {}
Then i have a controller:
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<Page<StoryResponse>> getStories(Pageable pageable) {
Page<StoryResponse> stories = storiesRepository.findAll(pageable).map(StoryResponseMapper::toStoryResponse);
return ResponseEntity.ok(stories);
}
Everything works fine, but I can't consume my endpoint using RestTemplate getForEntity method:
def entity = restTemplate.getForEntity(getLocalhost("/story"), new TypeReference<Page<StoryResponse>>(){}.class)
What class should I provide to successfully deserialize my Page of entities?

new TypeReference<Page<StoryResponse>>() {}
The problem with this statement is that Jackson cannot instantiate an abstract type. You should give Jackson the information on how to instantiate Page with a concrete type. But its concrete type, PageImpl, has no default constructor or any #JsonCreators for that matter, so you can not use the following code either:
new TypeReference<PageImpl<StoryResponse>>() {}
Since you can't add the required information to the Page class, It's better to create a custom implementation for Page interface which has a default no-arg constructor, as in this answer. Then use that custom implementation in type reference, like following:
new TypeReference<CustomPageImpl<StoryResponse>>() {}
Here are the custom implementation, copied from linked question:
public class CustomPageImpl<T> extends PageImpl<T> {
private static final long serialVersionUID = 1L;
private int number;
private int size;
private int totalPages;
private int numberOfElements;
private long totalElements;
private boolean previousPage;
private boolean firstPage;
private boolean nextPage;
private boolean lastPage;
private List<T> content;
private Sort sort;
public CustomPageImpl() {
super(new ArrayList<>());
}
#Override
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
#Override
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
#Override
public int getTotalPages() {
return totalPages;
}
public void setTotalPages(int totalPages) {
this.totalPages = totalPages;
}
#Override
public int getNumberOfElements() {
return numberOfElements;
}
public void setNumberOfElements(int numberOfElements) {
this.numberOfElements = numberOfElements;
}
#Override
public long getTotalElements() {
return totalElements;
}
public void setTotalElements(long totalElements) {
this.totalElements = totalElements;
}
public boolean isPreviousPage() {
return previousPage;
}
public void setPreviousPage(boolean previousPage) {
this.previousPage = previousPage;
}
public boolean isFirstPage() {
return firstPage;
}
public void setFirstPage(boolean firstPage) {
this.firstPage = firstPage;
}
public boolean isNextPage() {
return nextPage;
}
public void setNextPage(boolean nextPage) {
this.nextPage = nextPage;
}
public boolean isLastPage() {
return lastPage;
}
public void setLastPage(boolean lastPage) {
this.lastPage = lastPage;
}
#Override
public List<T> getContent() {
return content;
}
public void setContent(List<T> content) {
this.content = content;
}
#Override
public Sort getSort() {
return sort;
}
public void setSort(Sort sort) {
this.sort = sort;
}
public Page<T> pageImpl() {
return new PageImpl<>(getContent(), new PageRequest(getNumber(),
getSize(), getSort()), getTotalElements());
}
}

I know this thread is a little old, but hopefully someone will benefit from this.
#Ali Dehghani's answer is good, except that it re-implements what PageImpl<T> has already done. I considered this to be rather needless. I found a better solution by creating a class that extends PageImpl<T> and specifies a #JsonCreator constructor:
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.company.model.HelperModel;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import java.util.List;
public class HelperPage extends PageImpl<HelperModel> {
#JsonCreator
// Note: I don't need a sort, so I'm not including one here.
// It shouldn't be too hard to add it in tho.
public HelperPage(#JsonProperty("content") List<HelperModel> content,
#JsonProperty("number") int number,
#JsonProperty("size") int size,
#JsonProperty("totalElements") Long totalElements) {
super(content, new PageRequest(number, size), totalElements);
}
}
Then:
HelperPage page = restTemplate.getForObject(url, HelperPage.class);
This is the same as creating a CustomPageImpl<T> class but allows us to take advantage of all the code that's already in PageImpl<T>.

As "pathfinder" mentioned you can use exchange method of RestTemplate. However instead of passing ParameterizedTypeReference<Page<StoryResponse>>() you should pass ParameterizedTypeReference<PagedResources<StoryResponse>>(). When you get the response you could retrieve the content - Collection<StoryResponse>.
The code should look like this:
ResponseEntity<PagedResources<StoryResponse>> response = restTemplate.exchange(getLocalhost("/story"),
HttpMethod.GET, null, new ParameterizedTypeReference<PagedResources<StoryResponse>>() {});
PagedResources<StoryResponse> storiesResources = response.getBody();
Collection<StoryResponse> stories = storiesResources.getContent();
Apart from the content storiesResources holds page metadata and links too.
A more step-by-step explanation is available here: https://stackoverflow.com/a/46847429/8805916

If you use spring-cloud-openfeign you can use PageJacksonModule.
Just register PageJacksonModule in your object mapper:
final ObjectMapper mapper = new ObjectMapper()
mapper.registerModule(new PageJacksonModule());

If you looking at this thread, and if you try this answer
https://stackoverflow.com/a/44895867/8268335
You will meet the 2nd problem:
Can not construct instance of org.springframework.data.domain.Pageable
Then I find the perfect solution from here:
https://stackoverflow.com/a/42002709/8268335
I create the class RestPageImpl from the answer above and problem solved.

You can probably use exchange method of restTemplate and get the body from it..
Check the following answer https://stackoverflow.com/a/31947188/3800576.
This might help you

Related

Question on diamond operator for design pattern strategy

Small question regarding the diamond operator and design pattern strategy for Java, please.
I would like to implement a very specific requirement:
there are some objects to store (in my example called MyThingToStore)
and the requirement is to store them with different kinds of data structures, for comparison.
Therefore, I went to try with a strategy pattern, where each of the strategies is a different way to store, I think this pattern is quite lovely.
The code is as follows:
public class MyThingToStore {
private final String name;
public MyThingToStore(String name) {
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyThingToStore that = (MyThingToStore) o;
return Objects.equals(name, that.name);
}
#Override
public int hashCode() {
return Objects.hash(name);
}
#Override
public String toString() {
return "MyThingToStore{" +
"name='" + name + '\'' +
'}';
}
}
public class MyStorage {
private final StorageStrategy storageStrategy;
public MyStorage(StorageStrategy storageStrategy) {
this.storageStrategy = storageStrategy;
}
public void addToStore(MyThingToStore myThingToStore) {
storageStrategy.addToStore(myThingToStore);
}
public int getSize() {
return storageStrategy.getSize();
}
}
public interface StorageStrategy {
void addToStore(MyThingToStore myThingToStore);
int getSize();
}
public class StorageUsingArrayListStrategy implements StorageStrategy {
private final List<MyThingToStore> storeUsingArrayList = new ArrayList<>();
#Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingArrayList.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingArrayList.size();
}
}
public class StorageUsingHashSetStrategy implements StorageStrategy{
private final Set<MyThingToStore> storeUsingHashSet = new HashSet<>();
#Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingHashSet.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingHashSet.size();
}
}
public class Main {
public static void main(String[] args) {
final StorageStrategy storageStrategy = new StorageUsingArrayListStrategy();
final MyStorage myStorage = new MyStorage(storageStrategy);
myStorage.addToStore(new MyThingToStore("firstItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
System.out.println(myStorage.getSize()); //changing strategy will return a different size, working!
}
}
And this is working fine, very happy, especially tackled the requirement "easy to change the data structure to do the actual store".
(By the way, side question, if there is an even better way to do this, please let me know!)
Now, looking online at different implementations of strategy patterns, I see this diamond operator which I am having a hard time understanding:
MyThingToStore stays the same.
public class MyStorage {
private final StorageStrategy<MyThingToStore> storageStrategy; //note the diamond here
public MyStorage(StorageStrategy<MyThingToStore> storageStrategy) {
this.storageStrategy = storageStrategy;
}
public void addToStore(MyThingToStore myThingToStore) {
storageStrategy.addToStore(myThingToStore);
}
public int getSize() {
return storageStrategy.getSize();
}
#Override
public String toString() {
return "MyStorage{" +
"storageStrategy=" + storageStrategy +
'}';
}
}
public interface StorageStrategy<MyThingToStore> {
//note the diamond, and it will be colored differently in IDEs
void addToStore(MyThingToStore myThingToStore);
int getSize();
}
public class StorageUsingArrayListStrategy implements StorageStrategy<MyThingToStore> {
private final List<MyThingToStore> storeUsingArrayList = new ArrayList<>();
#Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingArrayList.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingArrayList.size();
}
}
public class StorageUsingHashSetStrategy implements StorageStrategy<MyThingToStore> {
private final Set<MyThingToStore> storeUsingHashSet = new HashSet<>();
#Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingHashSet.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingHashSet.size();
}
}
public class Main {
public static void main(String[] args) {
final StorageStrategy<MyThingToStore> storageStrategy = new StorageUsingArrayListStrategy();
final MyStorage myStorage = new MyStorage(storageStrategy);
myStorage.addToStore(new MyThingToStore("firstItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
System.out.println(myStorage.getSize()); //changing strategy will return a different size, working!
}
}
And both versions will yield the same good result, also be able to answer requirements.
My question is: what are the differences between the version without a diamond operator, and the version with the diamond operator, please?
Which of the two ways are "better" and why?
While this question might appear to be "too vague", I believe there is a reason for a better choice.
I think the confusion comes from how you named type parameter for StorageStrategy in your 2nd example.
Let's name it T for type instead. T in this case is just a placeholder to express what type of objects your StorageStrategy can work with.
public interface StorageStrategy<T> {
void addToStore(T myThingToStore);
int getSize();
}
E.g.
StorageStrategy<MyThingToStore> strategy1 = // Initialization
StorageStrategy<String> strategy2 = // Initialization
strategy1.addToStore(new MyThingToStore("Apple"));
// This works fine, because strategy2 accepts "String" instead of "MyThingToStore"
strategy2.addToStore("Apple");
// Last line doesn't work, because strategy1 can only handle objects of type "MyThingToStore"
strategy1.addToStore("Apple");
To make it work properly, you need to change your different StorageStrategy implementations to also include the type parameter.
public class StorageUsingHashSetStrategy<T> implements StorageStrategy<T> {
private final Set<T> storeUsingHashSet = new HashSet<>();
#Override
public void addToStore(T myThingToStore) {
storeUsingHashSet.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingHashSet.size();
}
}
And lastly you also want to have a type paremeter for MyStorage
public class MyStorage<T> {
private final StorageStrategy<T> storageStrategy;
public MyStorage(StorageStrategy<T> storageStrategy) {
this.storageStrategy = storageStrategy;
}
public void addToStore(T myThingToStore) {
storageStrategy.addToStore(myThingToStore);
}
public int getSize() {
return storageStrategy.getSize();
}
}
Now you can create a MyStorage and can use it to store essentially any object into it and not just MyThingToStore. Whether that is something you want or not is up to you.
In the second code sample in the declaration of the interface StorageStrategy<MyThingToStore>, MyThingToStore is a Type Variable.
I.e. it's not the actual type, only a placeholder for a type, like T. The common convention is to use single-letter generic type variables (T, U, R, etc.), otherwise it might look confusing like in this case.
Note that in the class declarations, like:
public class StorageUsingArrayListStrategy
implements StorageStrategy<MyThingToStore>
MyThingToStore is no longer a type variable, but the name of the class MyThingToStore because in this case parameterized interface is implemented by a non-parameterized class (i.e. the actual type known to the compile is expected to be provided).

How to define a function to return an array of an enum's values, using the child type (the enum implements an interface)?

I have a pool of many configuration settings, and each configuration setting has a pool of configuration options. Ideally, I want to be able to set a setting by using something like sendConfiguration(ID, OPTION).
Here is the Configuration class. It is an enum that maps the ID of the configuration to the set of options that are available for that configuration. For now, we'll just assume we have a configuration for the brightness setting.
public enum Configuration {
BRIGHTNESS(166, BrightnessConfigOptions.values());
private int configurationID;
private ConfigOption[] configOptions;
Configuration(int configurationID, ConfigOption[] configOptions) {
this.configurationID = configurationID;
this.configOptions = configOptions;
}
public int getConfigurationID() { return configurationID; }
public ConfigOption[] getConfigOptions() { return configOptions; }
}
BrightnessConfigOptions looks like the following:
public enum BrightnessConfigOptions implements ConfigOption {
DARK(1),
NORMAL(2),
BRIGHT(3),
VERY_BRIGHT(4);
private int configValue;
BrightnessConfigOptions(int configValue) {
this.configValue = configValue;
}
#Override
public int getConfigValue() { return configValue; }
}
And the ConfigOption interface looks like this:
public interface ConfigOption {
int getConfigValue();
}
So, as an example, the desired usage would be:
sendConfiguration(Configuration.BRIGHTNESS, Configuration.BRIGHTNESS.getConfigOptions().DARK)
...
void sendConfiguration(Configuration configuration, ConfigOption configOption) {
System.out.println(configuration.getConfigurationID());
System.out.println(configOption.getConfigValue());
}
This code does not work nicely because getConfigOptions returns ConfigOption[] and therefore I do not know the type, so I cannot write .DARK without casting first.
Either my design is wrong here, or I am forgetting something syntactically that would make this much easier. How can I make the typing work elegantly here?
Based on your example this would appear to do what you asked.
I also recommend you look into both EnumSet and EnumMap as they may provide additional alternatives.
interface ConfigOption {
int getConfigValue();
}
enum BrightnessConfigOptions implements ConfigOption {
DARK(1), NORMAL(2), BRIGHT(3), VERY_BRIGHT(4);
private int configValue;
BrightnessConfigOptions(int configValue) {
this.configValue = configValue;
}
public int getConfigValue() {
return configValue;
}
}
enum ColorConfigOptions implements ConfigOption {
RED(10), BLUE(20), GREEN(30);
private int configValue;
ColorConfigOptions(int id) {
this.configValue = id;
}
public int getConfigValue() {
return configValue;
}
}
enum Configuration {
BRIGHTNESS(166), COLOR(167);
private int configurationID;
private Configuration(int id) {
this.configurationID = id;
}
public int getConfigurationID() {
return configurationID;
}
}
public class EnumMapDemo {
public static void main(String[] args) {
new EnumMapDemo().start();
}
public void start() {
sendConfiguration(Configuration.BRIGHTNESS, BrightnessConfigOptions.DARK);
sendConfiguration(Configuration.BRIGHTNESS, BrightnessConfigOptions.BRIGHT);
sendConfiguration(Configuration.COLOR, ColorConfigOptions.RED);
}
void sendConfiguration(Configuration configuration,
ConfigOption c) {
System.out.println(configuration.getConfigurationID());
System.out.println(c.getConfigValue());
}
}

is my implementation of builder violates mutability

I'd like to know whether my implementation of QuestionBuilder violates mutability.
public class Question<T extends Serializable> implements Serializable {
private QuestionHolder<T> questionHolder;
private Question(QuestionHolder<T> questionHolder) {
this.questionHolder = questionHolder;
}
public String getId() {
return questionHolder.id;
}
public int getOrder() {
return questionHolder.order;
}
public QuestionType getType() {
return questionHolder.type;
}
public boolean isImmediate() {
return questionHolder.immediate;
}
public boolean isMandatory() {
return questionHolder.mandatory;
}
public List<T> getSelectedValues() {
return questionHolder.selectedValues;
}
public List<T> getPossibleValues() {
return questionHolder.possibleValues;
}
private static final class QuestionHolder<T extends Serializable> {
private String id;
private int order = 0;
private QuestionType type;
private boolean immediate;
private boolean mandatory;
private List<T> selectedValues;
private List<T> possibleValues;
}
public static final class QuestionBuilder<T extends Serializable> implements Builder<Question<T>> {
private QuestionHolder<T> questionHolder;
public QuestionBuilder(String id) {
questionHolder = new QuestionHolder<>();
questionHolder.id = id;
}
public QuestionBuilder withOrder(int order) {
questionHolder.order = order;
return this;
}
public QuestionBuilder withType(QuestionType questionType) {
questionHolder.type = questionType;
return this;
}
public QuestionBuilder withImmediate(boolean immediate) {
questionHolder.immediate = immediate;
return this;
}
public QuestionBuilder withMandatory(boolean mandatory) {
questionHolder.mandatory = mandatory;
return this;
}
public QuestionBuilder withSelectedValues(List<T> selectedValues) {
questionHolder.selectedValues = selectedValues;
return this;
}
public QuestionBuilder withPossibleValues(List<T> possibleValues) {
questionHolder.possibleValues = possibleValues;
return this;
}
public Question<T> build() {
Question<T> question = new Question<>(questionHolder);
questionHolder = null;
return question;
}
}
}
Or what should I adjust in order to resolve mutability issue. Any suggestions?
If you're worried about thread safety, then your code here is not necessarily thread safe.
It is possible that one thread calls build() and returns a Question pointing to a QuestionHolder. Even though build() sets the holder to null, another thread might not see that null, but instead see the old value of the field. If that other thread called any of your setters, it would potentially mutate the Holder that the Question class had already accessed.
In a single threaded application you would be fine.
As far as I can see, you are mutating the QuestionHolder with each builder call.
What I would do is:
1) Make all properties inside QuestionHolder private and don't create any setters at all.
2) Store each property inside the builder instance and create a new instance of QuestionHolder in the build method of the builder.
For example:
public Question<T> build() {
// DO ALL THE VALIDATIONS NEEDED
QuestionHolder holder = new QuestionHolder(id, order, type, inmediate, mandatory, selectedValues, possibleValues);
return new Question<>(questionHolder);
}
With these approach, you will be mutating the Builder, but that's ok for the Builder Pattern. You will obviously need to create a new Builder instance each time you want to create a Question. If you want to use the same Builder over and over again you will probably need to store some kind of structure inside it (a Map identified by Id, for example).

Generic Class and Method

I'm working on a pagination system for my java project, and I'd like to make it generic for my various JPA Models.
The problem (as far as I know) is that if I use generics, I will have to somehow cast the returned final value to work on it. How can I avoid that ?
Here's my code so far (absolutely not generic!) :
public interface Paginator {
public void setLimit(Integer limit);
public Page page(Integer page);
}
public class PicturesPaginator implements Paginator {
private Integer limit = 10;
private JPAQuery query;
private Long quantity;
public PicturesPaginator(String query, Object... params) {
this.query = Picture.find(query, params);
this.quantity = Picture.count(query, params);
}
#Override
public void setLimit(Integer limit) {
this.limit = limit;
}
#Override
public PicturesPage page(Integer page) {
if (page == null)
page = 1;
List<Picture> pictures = query.fetch(page, limit);
return new PicturesPage(pictures, quantity, page, limit);
}
}
public abstract class Page {
protected List<Picture> pictures;
protected Long quantity;
protected Integer page;
protected Integer limit;
public List<Picture> list() {
return pictures;
}
public Long count() {
return quantity;
}
public boolean hasNext() {
return (page * limit > quantity);
}
public boolean hasPrevious() {
return (page != 1);
}
public boolean hasOtherPages() {
return (hasNext() || hasPrevious());
}
public Integer nextPageNumber() {
if (!hasNext())
return null;
return (page + 1);
}
public Integer previousPageNumber() {
if (!hasPrevious())
return null;
return (page - 1);
}
public Integer currentPageNumber() {
return page;
}
}
public class PicturesPage extends Page {
public PicturesPage(List<Picture> pictures, Long quantity, Integer page, Integer limit) {
this.pictures = pictures;
this.quantity = quantity;
this.page = page;
this.limit = limit;
}
}
I would like to get rid of those PicturesPaginator and PicturesPage and make it generic, but the list() method from the abstract class Page would return a generic List (List<T> or List<GenericModel> since I use Play here).
What I would expect is this list() method to return the correct List, aka List<Picture> in my case. Is this possible ?
Note: I now there is a module for pagination in Play! Framework, my question is mainly for understanding more about java too :)
Thank you very much for your help, I really appreciate!
You can view my Play--Pagination module's source code to see how I handle this type of thing. I put my source on github.
What you want to do is make Page generic as well, and probably non-abstract:
public class Page<T> {
public List<T> list() {}
}
And instead of PicturesPage you could just do:
new Page<Picture>()
The Paginator interface would also need to be generified:
public interface Paginator {
public Page<T> page(Integer page);
}
Generifying PicturesPaginator would be harder since you invoke methods on the Picture class. Java's generics implementation erases types at runtime, so you'll have to deal with type tokens and reflection.
public abstract class GenericPaginator<T> {
public GenericPaginator() {
Class<T> typeToken = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
// use reflection to invoke the finders methods
}
}
public class PicturesPaginator extends GenericPaginator<Picture> {}
What I would expect is this list() method to return the correct List,
aka List in my case. Is this possible?
That's not just possible, that's what you automatically get if you use generics correctly. If you declare
public class Page<T extends GenericModel>{
protected List<T> items;
public List<T> list() {
return items;
}
}
and use it like this:
page = new Page<Picture>();
then page.list() will in fact return a List<Picture>, because T is a type parameter that is replaced by a concrete type when a Page is declared.
If I understand you correctly, the following may help:
Make Pace generic. Turn
public abstract class Page {
protected List<Picture> pictures;
public List<Picture> list() {
return pictures;
}
to:
public abstract class Page<Element> {
protected List<Element> elements;
public List<Element> list() {
return elements;
}
Than make PicturesPage concret:
public class PicturesPage extends Page<Picture> {
I'm not sure if this is what you require, but you can convert the Page class to this:
public abstract class Page<T> {
protected List<T> pictures;
protected Long quantity;
protected Integer page;
protected Integer limit;
public List<T> list() {
return pictures;
}
public Long count() {
return quantity;
}
public boolean hasNext() {
return (page * limit > quantity);
}
public boolean hasPrevious() {
return (page != 1);
}
public boolean hasOtherPages() {
return (hasNext() || hasPrevious());
}
public Integer nextPageNumber() {
if (!hasNext())
return null;
return (page + 1);
}
public Integer previousPageNumber() {
if (!hasPrevious())
return null;
return (page - 1);
}
public Integer currentPageNumber() {
return page;
}
If I understand you correctly, your problem with introducing generics here are lines like this:
this.query = Picture.find(query, params);
AFAIK you can't invoke static methods on generic types directly, so you'd have to use reflection here. In that case you might have to pass the class of the parameter type as a parameter (or get it from reflection data if it exists), find the method you want to invoke and invoke it.
It's something like this:
Class<T> clazz;
public Paginator (Class<T> clazz) {
this.clazz = clazz;
//note that you need to handle exceptions, I'll leave them out for brevity
Method findMethod = clazz.getMethod("find", String.class, Array.class );
this.query = findMethod.invoke(null, query, params);
}
Edit
As an alternative, pass a "finder" object to the generic Paginator and make it implement an interface that provides the find(...) and count(...) methods:
interface Finder<T> {
JPAQuery find( String query, Object... params);
Long count( String query, Object... params);
}
class Paginator<T, F extends Finder<T>> {
public Paginator(F finder, String query, Object... params) {
this.query = finder.find(query, params);
...
}
...
}

Json Jackson deserialization without inner classes

I have a question concerning Json deserialization using Jackson.
I would like to deserialize a Json file using a class like this one:
(taken from http://wiki.fasterxml.com/JacksonInFiveMinutes)
public class User
{
public enum Gender { MALE, FEMALE };
public static class Name {
private String _first, _last;
public String getFirst() { return _first; }
public String getLast() { return _last; }
public void setFirst(String s) { _first = s; }
public void setLast(String s) { _last = s; }
}
private Gender _gender;
private Name _name;
private boolean _isVerified;
private byte[] _userImage;
public Name getName() { return _name; }
public boolean isVerified() { return _isVerified; }
public Gender getGender() { return _gender; }
public byte[] getUserImage() { return _userImage; }
public void setName(Name n) { _name = n; }
public void setVerified(boolean b) { _isVerified = b; }
public void setGender(Gender g) { _gender = g; }
public void setUserImage(byte[] b) { _userImage = b; }
}
A Json file can be deserialized using the so called "Full Data Binding" in this way:
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(new File("user.json"), User.class);
My problem is the usage of the inner class "Name". I would like to do the same thing without using inner classes. The "User" class would became like that:
import Name;
import Gender;
public class User
{
private Gender _gender;
private Name _name;
private boolean _isVerified;
private byte[] _userImage;
public Name getName() { return _name; }
public boolean isVerified() { return _isVerified; }
public Gender getGender() { return _gender; }
public byte[] getUserImage() { return _userImage; }
public void setName(Name n) { _name = n; }
public void setVerified(boolean b) { _isVerified = b; }
public void setGender(Gender g) { _gender = g; }
public void setUserImage(byte[] b) { _userImage = b; }
}
This means to find a way to specify to the mapper all the required classes in order to perform the deserialization.
Is this possible? I looked at the documentation but I cannot find any solution.
My need comes from the fact that I use the Javassist library to create such classes, and it does not support inner or anonymous classes.
Thank you in advance
There should be no difference between the static inner class Name, and the top-level class of the same name. The Jackson runtime should not be able to meaningfully distinguish between the two situations.
Have you tried moving the Name class out of User, changing it into a top-level class? It should still work as before.
edit: I just tried this, and it works fine when Name is a top-level class. The example had it as an inner class for the sake of brevity, I suspect.
mr. Skaffman's answer is right on. The only additional thing to mention is that unlike JAXB, Jackson does not generally require you to specify classes you operate on, except for the root class (and not always even that, if you use Polymorphic Handling).

Categories

Resources