Spring Data REST return entity after create/update using projection - spring-data-rest

Spring Data REST has 2 properties (spring.data.rest.return-body-on-create, spring.data.rest.return-body-on-update) that are apparently true by default.
These properties make Spring return the submitted entity after create/update using POST/PUT/PATCH.
What I want is that the returned entity uses a projection to return its data so I tried submitting to this URL: http://localhost:8080/MYAPP/api/persons?projection=personProjection for new entities using POST and to this URL: http://localhost:8080/MYAPP/api/persons/1?projection=personProjection for old entities using PUT and PATCH.
All trials failed and I got the following exception: "Target bean of type com.sun.proxy.$Proxy231 is not of type of the persistent entity (com.test.entities.Person)!: com.sun.proxy.$Proxy231"
According to this question: After upgrade from Spring Boot 1.5 to 2.1 we get Target bean of type com.sun.proxy.$Proxy is not of type of the persistent entity
It seems that what I was trying to do was possible in older version of Spring Data REST.
So is this a bug ?
Or is there a workaround for this behavior without having to get the entity again in another back-end call or creating a custom controller for submissions ?
I am using Spring Boot v2.2.6.RELEASE
Thanks

Related

How to display a json response mapped pojo in sightly

I have a sling servlet that invokes a 3rd party api and fetches a json response. I have mapped the json response to a pojo class using Jackson. I now have to display this dynamically fetched and mapped response in sightly. How do i do that? I am stuck after the response mapping
With the new version of Sling Models, you can directly expose a model as a Servlet by specifying a resource type and the selector to use in your model annotations. When the Model is loaded into Apache Sling, it automatically registers a Servlet corresponding to the model, allowing you to with nearly zero additional code, create a Servlet to access a JSON representation of the model. That’s super cool!
The above life makes your Life Easier!!
You can have all your objects in Sling Model. Since the sling model acts as a servlet You can make the AJAX call and get a real-time response.
Please refer to this document.
https://blogs.perficient.com/2018/07/26/no-servlets-required-exporting-data-with-sling-models/
The correct path is:
HTL/Sightly -> Sling Model -> OSGi Service -> External API
So you have to extract the code that fetches the data into an OSGi service.
But please secure your code that calls the external API. As example if the External API is not responding or is extremely slow, it could consume all available threads of AEM. Then AEM could be completely unusable. To secure it, you could use as Example a Semaphore.
Assuming the JSON returned is arbitrary, the best thing to do is simply display it as a string. To do that, instead of mapping the JSON response to a POJO I would recommend adapting a Sling model to the response.
Then, you can set that Sling model to be the model in your sightly code, using data-sly-use.model, and in the Sling model constructor you can set the response value to an attribute of the sling model.
Then all you'd need to do is put that attribute in a ${} in the sightly html.
If the format/structure of the JSON isn't completely unknown, you could use the POJO in the sightly. Create some conditionals to test what attributes the POJO has, so you can put them into the sightly code.

How to write single objectMapper for spring-data-rest and to my #RestController class

I wrote a UnwrappingBeanSerializer for my entity. Currently this serializer was registered using ConfigureJacksonObjectMapper
This serializer is working fine for REST APIs generated from spring-data-rest. But I have a custom #RestController for the same entity, But it doesn't know about the serializer registered in spring-data-rest configuration.
I want to serialize my response with UnwrappingBeanSerializer both in spring-data-rest APIs and also to my custom controllers.
How to achieve this?
I also tried with #JsonSerialize on my entity class. But I am unable to create bean for unWrappingBeanSerializer with BeanSerializerBase
Regular #RestController and Spring Data REST controllers have different flows and configuration. If you are using Spring Data REST, you'd better use #RepositoryRestController for custom endpoints of the same resource, this will use the same Spring Data REST chain and its configuration, like the one you used in ConfigureJacksonObjectMapper, otherwise your ObjectMapper is visible only for Spring Data REST.
If you want to have #RestController and use the same ObjectMapper for both - you need to have two configurations: one for Spring Data REST (like you already have) and another for regular controllers, so just register it in Spring context (for instance, if you are using Spring MVC, see Customize the Jackson ObjectMapper).

Service Stack Redis in Web Api OData add EdmEntityObject / EdmEntityObjectCollection

We are able to add a normal POCO class to a Service Stack Redis client
IRedisTypedClient<Product> objRedisTypedClientNB = redisClient.As<Product>();
IRedisList<Product> objRedisListNB = objRedisTypedClientNB.Lists["Product"];
Product objNews = new Product(DateTime.Now.Ticks.ToString());
objRedisTypedClientNB.Lists["Product"].Push(objNews);
Adding products object to redis cache is fine
When using dynamic web api odata v4 service,
Metadata is created at runtime for each request based on url
How to add EdmEntityObject / EdmEntityObjectCollection into redis
EdmEntityObject objEntityObject = new EdmEntityObject((EdmEntityType)objEntityType);
objEntityObject.TrySetPropertyValue("Id", "test id");
IRedisTypedClient<EdmEntityObject> objRedisTypedClientEEOC = redisClient.As<EdmEntityObject>();
IRedisList<EdmEntityObject> objRedisListEEOC = objRedisTypedClientEEOC.Lists["EntityName"];
objRedisTypedClientEEOC.Lists["EntityName"].Add(objEntityObject); // throws error
Error
An unhandled exception of type 'System.StackOverflowException' occurred in Unknown Module.
How to resolve the error
How to add EdmEntityObject / EdmEntityObjectCollection 's instances into redis cache
Note:
1. Should not use POCO classes
2. ODataModel itself is created at runtime only
A System.StackOverflowException is indicative that you're trying to serialize non-serializable objects with cyclical dependencies which are not supported in any of ServiceStack's Serializers (and will also fail in most other Serializers).
Essentially EF DataModels have cyclical dependencies making them poor candidates for serialization. You should instead have them map to clean DTO's which can be serialized, or alternatively use any Micro ORM like OrmLite or Dapper which map resultsets into clean POCO models.
As a goal OrmLite ensures that all its features (inc. its Reference Support) maps to clean disconnected POCO's so they're always serializable and can be re-used in Services DTO's and other NoSQL datastores.

Why this EntityManagerSaveException?

I am using Silverlight 4 and DevForce 6.1.11.0
I have some POCO classes that implement EntityAspect.
When changes are saved via EntityManager.SaveChanges; DevForce does not save these POCO entities to the server, because these POCO entities are not part of EF.
Instead I send them to a webservice via WebClient.UploadStringAsync.
This works, expect when I am saving more than one entity of the same type. Then I get this exception:
EntityManagerSaveException: An entity with this key: PocoMyClass: 0,0
already exists in this entityManager
I have checked the cache, and there is no entity with that key.
The WebClient.UploadStringAsync still sends the data and everything gets saved, but the exception does not look good to customers.
How do I work around this exception?
The poco entities that I am having problems with are only supposed to live on the client, not the DevForce server. The reason is that only the client can access these on the local network.
So I am using WebClient.OpenReadAsync to read the data in and create the poco entities on the client. And then I use WebClient.UploadStringAsync when saving the poco entities.
When creating the poco entity and adding it to the entitymanager, I do like this:
var pocoEntity = new PocoMyClass();
pocoEntity.keyId = some integer;
…
entityManager.AddEntity(pocoEntity);
pocoEntity.EntityAspect.AcceptChanges();
After doing this I see that the properties for EntityVersion.Original of the poco entity only contains empty stuff (NULL´s and zero’s).
Is this the reason for the exception when saving?
How can I manipulate EntityVersion.Original when the entity does not come from the DevForce server?

Is it possible to inject ResourceInfo into EntityProvider, such as MessageBodyReader and MessageBodyWriter?

There is a requirement:
For each RESTful resource method, there is a set of OXM metadata file. I need to load those files while creating JAXBContext. So I need to know per-request ResourceInfo, and then mapping from some Annotation on the Resource Method, which can indicate which set of OXM metadata file should be loaded.
Is ResourceInfo per-request?
Can I obtain the Method (resource method) per request inside EntityProvider, such as MessageBodyReader and MessageBodyWriter?
Which do you prefer, OXM metadata between JPA Entity and XML/JSON or between TO and XML/JSON? Since I assume per service TO can customize the view of domain class to client.
I had similar problem. After several hours of research I got what I want by directly injecting provider capable to resolve resource method:
#Inject
Provider<RoutingContext> routingContextProvider;
log.info("routing method == " + routingContextProvider.get().getResourceMethod());
After a few research and experiments, finally I made the breakthrough.
Is ResourceInfo per-request?
[ANS] Yes, as documented in javadoc.
Can I obtain the Method (resource method) per request inside EntityProvider, such as MessageBodyReader and MessageBodyWriter?
[ANS] There is a defect in JIRA which is very similar with this, it says that ResourceInfo cannot be injected into Filters, interceptors as found, maybe it will be fixed at some version for glassfish.jersey team.
Which do you prefer, OXM metadata between JPA Entity and XML/JSON or between TO and XML/JSON? Since I assume per service TO can customize the view of domain class to client.
[ANS] Finally I decide to use TO other than JPA Entities as a concept of module exports. Because their development lifecycle are different, and there is also some restrictions to use JPA Entity with OXM.
a. Development Lifecycle: TO is designed as exportable with interfaces to other modules or upper layer services, they are suppose to be determined while case designing phase according to requirement, and since it's delivered with interface, the content of TO should be relatively stable, changes should also follow versioning management. But entity design is much more flexible, and it changes time to time, those changes should be hide from the clients of this module, and sometime there is business logics inside. I know there are some company or architecture expose entities to other modules, or there is only 1 module, so it does not matter. But I choose to hide domain classes.
b. While using JPA Entity exposing at service layer, then MOXy can be a good choice with providing Mapping JPA Entity and RESTful Entity body. Then due to some Lazy Loading requirement, ORM frameworks does some class transformation or byte code generation work implicitly, and some additional Lazy loading related fields will be loaded at runtime or generated at compile time, and those fields will lead some boring errors in MOXy while OXM using FIELD as accessor-type. You have to switch to PROPERTY mode or to define the god-know fields in your OXM metadata to hide them. Otherwise Getters and Setters had to be defined on JPA Entity class, which will lead to additional exposure.
And introduce TO will reduce the complexity of OXM work, much less metadata files will be used, with annotations on TO class, there can be zero OXM Metadata files, and I think OXM Metadata files are designed to integrate different systems other than connecting modules inside one system. So the answer is :
I PERFER TO than JPA Entities.