I am showing some data to the user:
{
"id": 3,
"name": "AB:11",
"description": "AB:11 is an Imperial Black Barley Wine brewed with ginger, black raspberries and chipotle peppers. A 12.8% rollercoaster of ginger zestiness and chipotle smokiness, all bound together with dark berry tartness and the decadent residual body of a Black Barley Wine.",
"method": {
"id": 3,
"mash_temp": [
{
"id": 6,
"temp": {
"value": 68,
"unit": "celsius"
}
}
]
}
}
But, I want to show it without "method" I only need to show what is inside "mesh_temp" field,so it would be something like this:
"id": 3,
"name": "AB:11",
"description": "AB:11 is an Imperial Black Barley Wine brewed with ginger, black raspberries and chipotle peppers. A 12.8% rollercoaster of ginger zestiness and chipotle smokiness, all bound together with dark berry tartness and the decadent residual body of a Black Barley Wine.",
"mash_temp": [
{
"temp": {
"value": 68,
"unit": "celsius"
}
}
]
}
Also, like you can see in first example I don't want to show id of the mesh_temp
Those are my Entities:
Beer: Beer class
Method: Method class
Mash Temp: MashTemp class
Temp: Temp class
So just to summarize: I want to show only: id, name, description and mash_temp field (without id). Any advices how to do this?
The simplest way is to create a DTO that is used in the response on your API with exactly the attributes you want. This is in fact a suggested pattern exactly because of use cases similar to this one: when your internal model is different from the model you want to make available via your API.
Just like I answered your other question, I would suggest a DTO approach with Blaze-Persistence Entity-Views: How to show data to user with DTO
Create a Model class as shown below and set the required fields
public class MyData {
private Long id;
private String name;
private String description;
private List<MashTemp> mash_temp;
}
class MashTemp {
private String temp;
private Integer value;
private String unit;
}
Related
Before I start questioning let me give you a simplified example of my case:
Imagine you have Views:
public final class Views {
public interface Id { }
public interface IdText extends Id { }
public interface FullProfile extends IdText { }
}
You also have a class User which has subscribers that are of the same type User.
The properties id and username are serialized in the Views.IdText.class view. And the property subscribers is serialized in the Views.FullProfile.class view.
#Entity
public class User implements UserDetails {
#Id
#JsonView(Views.IdText.class)
private Long id;
#JsonView(Views.IdText.class)
private String username;
#JsonIdentityReference
#JsonIdentityInfo(
property = "id",
generator = ObjectIdGenerators.PropertyGenerator.class
)
#JsonView(Views.FullProfile.class)
private Set<User> subscribers = new HashSet<>();
}
And a controller (ProfileController) that has a method called get that returns a user's profile.
#RestController
public class ProfileController {
#GetMapping("{id}")
#JsonView(Views.FullProfile.class)
public User get(#PathVariable("id") User user) {
// ... some service methods that has the necessary logic.
return user;
}
}
As you can see, the method serializes the user's profile in the Views.FullProfile.class view, so the output is:
{
"id": 39,
"username": "ryan",
"subscribers": [
{
"id": 42,
"username": "elliott",
"subscribers": [
{
"id": 432,
"username": "oliver",
"subscribers": [
{
"id": 2525,
"username": "james",
"subscribers": [
39,
432
]
},
{
// ... a lot of useless data goes on.
}
]
},
{
"id": 94923,
"username": "lucas",
"subscribers": [
345, 42
]
}
]
},
{
"id": 345,
"username": "jocko",
"subscribers": [
94923
]
}
]
}
When a user's profile is being serialized, I don't need the user's subscribers to be serialized in the Views.FullProfile.class view
but in the Views.IdText.class view so that the output would be:
{
"id": 39,
"username": "ryan",
"subscriptions": [
{
"id": 42,
"username": "elliott"
},
{
"id": 345,
"username": "jocko"
}
]
}
How can I make jackson to use different views on nested entities of the same type?
Or what else do I have to do to make that happen?
After some time of continuous searching I found someone issued the same problem on Github: #JsonIgnoreProperties should support nested properties #2940
As stated in that issue:
No plans to ever implement this (due to delegating design, will not be possible with current Jackson architecture), closing.
We are building a headless CMS with the wagtail API.
Our main model became very long, to make the representation cleaner and more easily accessible for the Frontend,
I am trying to group the different fields of my PageModel into sections.
But I don't manage to serialize the nested ImageField.
This is my PageModel:
class LandingPage(Page):
…
introduction_headline= models.CharField()
introduction_text = RichTextField()
introduction_icon = models.ForeignKey(
'main.CaptionImage',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name = '+',
)
…
I would like to group those fields into one section in the api, like so:
{
"id": 3,
"meta": {…},
"introduction_section": {
"introduction_headline": "intro head",
"introduction_text": "<p>intro text</p>",
"introduction_image": {
"id": 1,
"meta": {
"type": "main.CaptionImage",
"detail_url": "http://localhost/api/v2/images/1/",
"download_url": "/media/original_images/1.png"
},
"title": "german_design_image.png",
"caption": "Pretty Image"
},
},…
I managed to accomplish this in parts by writing a custom IntroductionSection - serializer:
class LandingPage(Page):
…
api_fields = [
APIField('introduction_section', serializer=IntroductionSectionField(source='*')),
…
]
class IntroductionSectionField(Field):
read_only = True
write_only = False
def to_representation(self, value):
return {
"introduction_headline" : value.introduction_headline,
"introduction_text" : value.introduction_text,
"introduction_image" : ?
}
But I simply can't figure out how to serialize the nested Image Field?
I want the same representation as the standard nested-relation-representation of the page model.
I tried around with get_related_field() method of the PageModel, tried to call the ImageSerializer, and all sorts of other things.
Currently I'm using SpringData to build my restful project.
I'm using Page findAll(Pageable pageable, X condition, String... columns); ,this method .The result looks like this:
{
"content": [
{
"id": 2,
"ouId": 1,
"pClassId": 3,
"isPublic": 0,
"accessMethod": 3,
"modifierName": null
}
],
"last": true,
"totalPages": 1,
"totalElements": 3,
"number": 0,
"size": 10,
"sort": [
{
"direction": "DESC",
"property": "id",
"ignoreCase": false,
"nullHandling": "NATIVE",
"ascending": false,
"descending": true
}
],
"first": true,
"numberOfElements": 3
}
The question is how to hide some specific json field in the content ?
And #JsonIgnore annotation is not flexible , the fields I need in different APIs are different.
I tried to write an annotation ,but when processing the Page ,I found that the content is unmodifiable .
So , hope that someone could help me with it.
If you don't want to put annotations on your Pojos you can also use Genson.
Here is how you can exclude a field with it without any annotations (you can also use annotations if you want, but you have the choice).
Genson genson = new Genson.Builder().exclude("securityCode", User.class).create();
// and then
String json = genson.serialize(user);
OR using flexjson
import flexjson.JSONDeserializer;
import flexjson.JSONSerializer;
import flexjson.transformer.DateTransformer;
public String toJson(User entity) {
return new JSONSerializer().transform(new DateTransformer("MM/dd/yyyy HH:mm:ss"), java.util.Date.class)
.include("wantedField1","wantedField2")
.exclude("unwantedField1").serialize(entity);
}
You have to use a custom serialize like the following:
#JsonComponent
public class MovieSerializer extends JsonSerializer<Movie> {
#Override
public void serialize(Movie movie, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartObject();
// The basic information of a movie
jsonGenerator.writeNumberField("id", movie.getId());
jsonGenerator.writeStringField("name", movie.getName());
jsonGenerator.writeStringField("poster", movie.getPoster());
jsonGenerator.writeObjectField("releaseDate", movie.getReleaseDate());
jsonGenerator.writeObjectField("runtime", movie.getRuntime());
jsonGenerator.writeStringField("storyline", movie.getStoryline());
jsonGenerator.writeStringField("rated", movie.getRated());
jsonGenerator.writeNumberField("rating", movie.getRating());
jsonGenerator.writeEndObject();
}
}
And then annotate your model class with: #JsonSerialize(using = MovieSerializer.class)
if I have a collection of books :-
{author: "tolstoy", title:"war & peace", price:100, pages:800}
{author: "tolstoy", title:"Ivan Ilyich", price:50, pages:100}
and if i want a result like this after grouping them by author :-
{ author: "tolstoy",
books: [
{author: "tolstoy", title:"war & peace", price:100, pages:800}
{author: "tolstoy", title:"Ivan Ilyich", price:50, pages:100}
]
}
using raw mongo queries I can do something like this:-
{$group: {
_id: "$author",
books:{$push: {author:"$author", title:"$title", price:"$price", pages:"$pages"}},
}}
But how do I do this using spring , I tried something like this:-
private GroupOperation getGroupOperation() {
return group("author").push("title").as("title").push("price").as("price").push("pages").as("pages");
}
but this does not seem to work. Any help would be appreciated.
UPDATE:-
I used the solution as in the link suggested by #Veeram and it works great but I ran into another issue when I project it. I have my projection class which looks like:-
public class BookSummary{
private String author;
private List<Book> bookList;
//all getters and setters below
}
The group method looks like this:-
private GroupOperation getGroupOperation() {
return group("author").push(new BasicDBObject("id","$_id").append("title","$title").append("pages","$pages").append("price","$price")).as("bookList");
}
the projection method looks like this:-
private ProjectionOperation getProjectOperation() {
return project("author").and("bookList").as("bookList");
}
and the final aggregation operation:-
mongoTemplate.aggregate(Aggregation.newAggregation(groupOperation,projectionOperation), Book.class, BookSummary.class).getMappedResults();
However this gives the result:-
[
{
"author": null,
"bookList": [
{
"id": null,
"title": "title1",
"pages": "100",
"price":"some price"
},
{
"id": null,
"title": "title2",
"pages": "200",
"price":"some price"
}
]
}
]
Why is the author and id null here? Any help would be appreciated
You should be projecting using _id instead in the project phase.
private ProjectionOperation getProjectOperation() {
return project("_id").and("bookList").as("bookList");
}
Looking for a LINQ implementation to handle following use case.
Pesudo definitions of object:
class Product{
int Id;
string Name;
IList<ProductAttribute> ProductAttributes;
}
class ProductAttribute{
int Id;
string Name;
string Value;
}
I have collection of products that look something like:
[
{"Name":"Red Large Shirt", "ProductAttributes": [{"Name": "Color", Value:"Red"},{"Name":"Size", "Value":"Large"}, {"Name":"Type", "Value":"Shirt"}]},
{"Name":"Red Small Shirt", "ProductAttributes": [{"Name": "Color", Value:"Red"},{"Name":"Size", "Value":"Small"}, {"Name":"Type", "Value":"Shirt"}]},
{"Name":"Red Large Pant", "ProductAttributes": [{"Name": "Color", Value:"Red"},{"Name":"Size", "Value":"Large"}, {"Name":"Type", "Value":"Pant"}]},
{"Name":"Blue Large Shirt", "ProductAttributes": [{"Name": "Color", Value:"Blue"},{"Name":"Size", "Value":"Large"}, {"Name:"Type", "Value":"Shirt"}]},
]
I need a LINQ statement that returns list of products that match certain attributes.
E.g. Return list of product where ProductAttribute ("Name"="Size" && "Value"="Large") && ("Name"="Color" && "Value" = "Red")
Thanks
You need to use .Any() or .Contains() extension. For example,
products.Where(p=>p.ProductAttributes.Any(a=>a...condition here for attributes))