Can you use RequestFactory's .with() method with named queries? - sql

I'm trying to make a call to a database using RequestFactory with Hibernate/JPA, and I want to retrieve a list of entities with embedded entities returned as well. I know that the .with() method works for methods like .find(), but it doesn't seem to work with custom queries.
The current way I'm doing it is as follows:
I used a named query in the entity class for the query. (Primary Entity is Name, embedded entity is a Suffix entity called nameSuffix)
#NamedQueries({ #NamedQuery(name = "Query.name", query = "select * from NameTable") })
Then in the service class, the .list() method, which is what I'd like to call with RequestFactory, is as follows.
public List<Name> list() {
return emp.get().createNamedQuery("Query.name").getResultList();
}
Finally, this is how I make the call in my client side code:
NameRequest context = requestFactory.createNameRequest();
context.list().with("nameSuffix").fire(new Receiver<List<NameProxy>>(){
public void onSuccess(List<NameProxy> response) {
String suff = response.get(0).getNameSuffix().getText();
}
});
In the above code, it says that getNameSuffix() returns null, which would imply that .with("nameSuffix") does not work with the .list() call like it does with the standard .find() method.
Is there a way to build a call that would return a list of entities and their embedded entities using .with(), or do I need to do it another way? If I need to do it another way, has anyone figured out a good way of doing it?

I think you misunderstood what the method with() is thought for, unless you had a method getNameSuffix which returns the NameSuffixentity. This is what the documentation says about it:
When querying the server, RequestFactory does not automatically populate relations in the object graph. To do this, use the with() method on a request and specify the related property name as a String
So, what you have to pass to the method is a list of the name of the child entities you want to retrieve. I hope this example could be helpful:
class A {
String getS(){return "s-a"}
B getB(){return new B();}
}
class B {
String getS(){return "s-b";}
C getC(){return new C();}
}
class C {
String getS(){return "s-c";}
}
context.getA().fire(new Receiver<A>(){
public void onSuccess(A response) {
// return 's-a'
response.getS();
// trhows a NPE
response.getB().getS();
}
});
context.getA().with("b").fire(new Receiver<A>(){
public void onSuccess(A response) {
// return 's-a'
response.getS();
// return 's-b'
response.getB().getS();
// trhows a NPE
response.getB().getC().getS();
}
});
context.getA().with("b.c").fire(new Receiver<A>(){
public void onSuccess(A response) {
// return 's-a'
response.getS();
// return 's-b'
response.getB().getS();
// return 's-c'
response.getB().getC().getS();
}
});

Related

Chaining Reactive Asynchronus calls in spring

I’m very new to the SpringReactor project.
Until now I've only used Mono from WebClient .bodyToMono() steps, and mostly block() those Mono's or .zip() multiple of them.
But this time I have a usecase where I need to asynchronously call methods in multiple service classes, and those multiple service classes are calling multiple backend api.
I understand Project Reactor doesn't provide asynchronous flow by default.
But we can make the publishing and/or subscribing on different thread and make code asynchronous
And that's what I am trying to do.
I tried to read the documentation here reactor reference but still not clear.
For the purpose of this question, I’m making up this imaginary scenario. that is a little closer to my use case.
Let's assume we need to get a search response from google for some texts searched under images.
Example Scenario
Let's have an endpoint in a Controller
This endpoint accepts the following object from request body
MultimediaSearchRequest{
Set<String> searchTexts; //many texts.
boolean isAddContent;
boolean isAddMetadata;
}
in the controller, I’ll break the above single request object into multiple objects of the below type.
MultimediaSingleSearchRequest{
String searchText;
boolean isAddContent;
boolean isAddMetadata;
}
This Controller talks to 3 Service classes.
Each of the service classes has a method searchSingleItem.
Each service class uses a few different backend Apis, but finally combines the results of those APIs responses into the same type of response class, let's call it MultimediaSearchResult.
class JpegSearchHandleService {
public MultimediaSearchResult searchSingleItem
(MultimediaSingleSearchRequest req){
return comboneAllImageData(
getNameApi(req),
getImageUrlApi(req),
getContentApi(req) //dont call if req.isAddContent false
)
}
}
class GifSearchHandleService {
public MultimediaSearchResult searchSingleItem
(MultimediaSingleSearchRequest req){
return comboneAllImageData(
getNameApi(req),
gitPartApi(req),
someRandomApi(req),
soemOtherRandomApi(req)
)
}
}
class VideoSearchHandleService {
public MultimediaSearchResult searchSingleItem
(MultimediaSingleSearchRequest req){
return comboneAllImageData(
getNameApi(req),
codecApi(req),
commentsApi(req),
anotherApi(req)
)
}
}
In the end, my controller returns the response as a List of MultimediaSearchResult
Class MultimediaSearchResponse{
List< MultimediaSearchResult> results;
}
If I want to use this all asynchronously using the project reactor. how to achieve it.
Like calling searchSingleItem method in each service for each searchText asynchronously.
Even within the services call each backend API asynchronously (I’m already using WebClient and converting response bodyToMono for backend API calls)
First, I will outline a solution for the upper "layer" of your scenario.
The code (a simple simulation of the scenario):
public class ChainingAsyncCallsInSpring {
public Mono<MultimediaSearchResponse> controllerEndpoint(MultimediaSearchRequest req) {
return Flux.fromIterable(req.getSearchTexts())
.map(searchText -> new MultimediaSingleSearchRequest(searchText, req.isAddContent(), req.isAddMetadata()))
.flatMap(multimediaSingleSearchRequest -> Flux.merge(
classOneSearchSingleItem(multimediaSingleSearchRequest),
classTwoSearchSingleItem(multimediaSingleSearchRequest),
classThreeSearchSingleItem(multimediaSingleSearchRequest)
))
.collectList()
.map(MultimediaSearchResponse::new);
}
private Mono<MultimediaSearchResult> classOneSearchSingleItem(MultimediaSingleSearchRequest req) {
return Mono.just(new MultimediaSearchResult("1"));
}
private Mono<MultimediaSearchResult> classTwoSearchSingleItem(MultimediaSingleSearchRequest req) {
return Mono.just(new MultimediaSearchResult("2"));
}
private Mono<MultimediaSearchResult> classThreeSearchSingleItem(MultimediaSingleSearchRequest req) {
return Mono.just(new MultimediaSearchResult("3"));
}
}
Now, some rationale.
In the controllerEndpoint() function, first we create a Flux that will emit every single searchText from the request. We map these to MultimediaSingleSearchRequest objects, so that the services can consume them with the additional metadata that was provided with the original request.
Then, Flux::flatMap the created MultimediaSingleSearchRequest objects into a merged Flux, which (as opposed to Flux::concat) ensures that all three publishers are subscribed to eagerly i.e. they don't wait for one another. It works best on this exact scenario, when several independent publishers need to be subscribed to at the same time and their order is not important.
After the flat map, at this point, we have a Flux<MultimediaSearchResult>.
We continue with Flux::collectList, thus collecting the emitted values from all publishers (we could also use Flux::reduceWith here).
As a result, we now have a Mono<List<MultimediaSearchResult>>, which can easily be mapped to a Mono<MultimediaSearchResponse>.
The results list of the MultimediaSearchResponse will have 3 items for each searchText in the original request.
Hope this was helpful!
Edit
Extending the answer with a point of view from the service classes as well. Assuming that each inner (optionally skipped) call returns a different type of result, this would be one way of going about it:
public class MultimediaSearchResult {
private Details details;
private ContentDetails content;
private MetadataDetails metadata;
}
public Mono<MultimediaSearchResult> classOneSearchSingleItem(MultimediaSingleSearchRequest req) {
return Mono.zip(getSomeDetails(req), getContentDetails(req), getMetadataDetails(req))
.map(tuple3 -> new MultimediaSearchResult(
tuple3.getT1(),
tuple3.getT2().orElse(null),
tuple3.getT3().orElse(null)
)
);
}
// Always wanted
private Mono<Details> getSomeDetails(MultimediaSingleSearchRequest req) {
return Mono.just(new Details("details")); // api call etc.
}
// Wanted if isAddContent is true
private Mono<Optional<ContentDetails>> getContentDetails(MultimediaSingleSearchRequest req) {
return req.isAddContent()
? Mono.just(Optional.of(new ContentDetails("content-details"))) // api call etc.
: Mono.just(Optional.empty());
}
// Wanted if isAddMetadata is true
private Mono<Optional<MetadataDetails>> getMetadataDetails(MultimediaSingleSearchRequest req) {
return req.isAddMetadata()
? Mono.just(Optional.of(new MetadataDetails("metadata-details"))) // api call etc.
: Mono.just(Optional.empty());
}
Optionals are used for the requests that might be skipped, since Mono::zip will fail if either of the zipped publishers emit an empty value.
If the results of each inner call extend the same base class or are the same wrapped return type, then the original answer applies as to how they can be combined (Flux::merge etc.)

How to retrieve RouteValues in ActionSelector in ASP.NET Core

I've created a GitHub repo to better understand the problem here. I have two actions on two different controllers bound to the same route.
http://localhost/sameControllerRoute/{identifier}/values
[Route("sameControllerRoute")]
public class FirstController : Controller
{
public FirstController()
{
// different EF Core DataContext than SecondController and possibly other dependencies than SecondController
}
[HttpGet("{identifier}/values")]
public IActionResult Values(string identifier, DateTime from, DateTime to) // other parameters than SecondController/Values
{
return this.Ok("Was in FirstController");
}
}
[Route("sameControllerRoute")]
public class SecondController : Controller
{
public SecondController()
{
// different EF Core DataContext than FirstController and possibly other dependencies than FirstController
}
[HttpGet("{identifier}/values")]
public IActionResult Values(string identifier, int number, string somethingElse) // other parameters than FirstController/Values
{
return this.Ok("Was in SecondController");
}
}
Since there are two matching routes, the default ActionSelector fails with:
'[...] AmbiguousActionException: Multiple actions matched. [...]'
which is comprehensible.
So I thought I can implement my own ActionSelector. In there I would implement the logic that resolves the issue of multiple routes via same logic depending on the 'identifier' route value (line 27 in code)
If 'identifier' value is a --> then FirstController
If 'identifier' value is b --> then SecondController
and so on...
protected override IReadOnlyList<ActionDescriptor> SelectBestActions(IReadOnlyList<ActionDescriptor> actions)
{
if (actions.HasLessThan(2)) return base.SelectBestActions(actions); // works like base implementation
foreach (var action in actions)
{
if (action.Parameters.Any(p => p.Name == "identifier"))
{
/*** get value of identifier from route (launchSettings this would result in 'someIdentifier') ***/
// call logic that decides whether value of identifier matches the controller
// if yes
return new List<ActionDescriptor>(new[] { action }).AsReadOnly();
// else
// keep going
}
}
return base.SelectBestActions(actions); // fail in all other cases with AmbiguousActionException
}
But I haven't found a good solution to get access to the route values in ActionSelector. Which is comprehensible as well because ModelBinding hasn't kicked in yet since MVC is still trying to figure out the Route.
A dirty solution could be to get hold of IHttpContextAccessor and regex somehow against the path.
But I'm still hoping you could provide a better idea to retrieve the route values even though ModelBinding hasn't happend yet in the request pipeline.
Not sure that you need to use ActionSelector at all for your scenario. Accordingly, to provided code, your controllers works with different types of resources (and so they expect different query parameters). As so, it is better to use different routing templates. Something like this for example:
FirstController: /sameControllerRoute/resourceA/{identifier}/values
SecondController: /sameControllerRoute/resourceB/{identifier}/values
In the scope of REST, when we are talking about /sameControllerRoute/{identifier}/values route template, we expect that different identifier means the same resource type, but different resource name. And so, as API consumers, we expect that all of the following requests are supported
/sameControllerRoute/a/values?from=20160101&to=20170202
/sameControllerRoute/b/values?from=20160101&to=20170202
/sameControllerRoute/a/values?number=1&somethingElse=someData
/sameControllerRoute/b/values?number=1&somethingElse=someData
That is not true in your case
I ended up implementing the proposed solution by the ASP.NET team. This was to implement an IActionConstrain as shown here:
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
namespace ActionConstraintSample.Web
{
public class CountrySpecificAttribute : Attribute, IActionConstraint
{
private readonly string _countryCode;
public CountrySpecificAttribute(string countryCode)
{
_countryCode = countryCode;
}
public int Order
{
get
{
return 0;
}
}
public bool Accept(ActionConstraintContext context)
{
return string.Equals(
context.RouteContext.RouteData.Values["country"].ToString(),
_countryCode,
StringComparison.OrdinalIgnoreCase);
}
}
}
https://github.com/aspnet/Entropy/blob/dev/samples/Mvc.ActionConstraintSample.Web/CountrySpecificAttribute.cs

Return multiple validation failures from a single Custom() rule?

Using FluentValidation and a Custom() rule, I want to be able to validate a collection of child objects, and return a ValidationFailure for each child object that is invalid.
I can't use a collection validator because the child object doesn't contain the right information to execute the rule - it must run in the context of the parent.
However the Custom() API limits me to returning a single ValidationFailure or nothing at all.
Is there a pattern I can use that allows a single rule to generate multiple errors?
I found a good solution - use AddRule() with a DelegateValidator.
public MyValidator : AbstractValidator<MyClass>
{
public MyValidator()
{
AddRule(new DelegateValidator<MyClass>(MyRule));
}
private IEnumerable<ValidationFailure> MyRule(
MyClass instance,
ValidationContext<MyClass> context)
{
var result = new List<ValidationFailure>();
// add as many failures to the list as you want:
var message = "This is not a valid message";
result.Add(new ValidationFailure(nameof(MyClass.SomeProperty), message));
return result;
}
}

CakePHP 3 integeration test without a model/entity

I'm trying to test a controller function...
I want to test a couple of things:
A) That it throws an invalid request exception when a certain argument is used
B) That it works correctly when the correct argument is made.
I've written some unit tests and those all seem cool. The only documentation I can find on this is http://book.cakephp.org/3.0/en/development/testing.html but the integration testing, whilst interesting and potentially useful, I can't seem to get how I am suppose to be implement it without using fixtures (which I don't want to do necessarily).
namespace App\Test\TestCase\Controller;
use Cake\ORM\TableRegistry;
use Cake\TestSuite\IntegrationTestCase;
class MusterControllerTest extends IntegrationTestCase
{
public function testIn()
{
$this->in();
$this->setExpectedException('Invalid request');
}
}
class MusterController extends AppController {
public $helpers = array('Address');
public function beforeFilter(Event $event) {
$this->Auth->allow('in');
$this->layout = 'blank';
$this->autoRender = false;
$this->loadComponent('Rule');
parent::beforeFilter($event);
}
public function in($param = null){
if (!$this->request->is(array('post', 'put')) || $this->request->data('proc')!='yada' || is_null($param)){
throw new NotFoundException(__('Invalid request'));
}
$this->processRequest($this->request->data('hit'), $this->request->data('proc'), $param);
}
Pointers appreciated.
The IntegrationTestCase class, as its name implies, is meant for integration testing. That is, it will be testing the interaction between the controller and any other class it uses for rendering a response.
There is another way of testing controller, which is more difficult to accomplish, but allows you to test controller methods in isolation:
public function testMyControllerMethod()
{
$request = $this->getMock('Cake\Network\Request');
$response = $this->getMock('Cake\Network\Response');
$controller = new MyController($request, $response);
$controller->startupProcess();
// Add some assertions and expectations here
// For example you could assing $controller->TableName to a mock class
// Call the method you want to test
$controller->myMethod('param1', 'param2');
}

Can I stop my WCF generating ArrayOfString instead of string[] or List<string>

I am having a minor problem with WCF service proxies where the message contains List<string> as a parameter.
I am using the 'Add Service reference' in Visual Studio to generate a reference to my service.
// portion of my web service message
public List<SubscribeInfo> Subscribe { get; set; }
public List<string> Unsubscribe { get; set; }
These are the generated properties on my MsgIn for one of my web methods.
You can see it used ArrayOfString when I am using List<string>, and the other takes List<SubscribeInfo> - which matches my original C# object above.
[System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
public System.Collections.Generic.List<DataAccess.MailingListWSReference.SubscribeInfo> Subscribe {
get {
return this.SubscribeField;
}
set {
if ((object.ReferenceEquals(this.SubscribeField, value) != true)) {
this.SubscribeField = value;
this.RaisePropertyChanged("Subscribe");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
publicDataAccess.MailingListWSReference.ArrayOfString Unsubscribe {
get {
return this.UnsubscribeField;
}
set {
if ((object.ReferenceEquals(this.UnsubscribeField, value) != true)) {
this.UnsubscribeField = value;
this.RaisePropertyChanged("Unsubscribe");
}
}
}
The ArrayOfString class generated looks like this. This is a class generated in my code - its not a .NET class. It actually generated me a class that inherits from List, but didn't have the 'decency' to create me any constructors.
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.CollectionDataContractAttribute(Name="ArrayOfString", Namespace="http://www.example.com/", ItemName="string")]
[System.SerializableAttribute()]
public class ArrayOfString : System.Collections.Generic.List<string> {
}
The problem is that I often create my message like this :
client.UpdateMailingList(new UpdateMailingListMsgIn()
{
Email = model.Email,
Name = model.Name,
Source = Request.Url.ToString(),
Subscribe = subscribeTo.ToList(),
Unsubscribe = unsubscribeFrom.ToList()
});
I really like the clean look this gives me.
Now for the actual problem :
I cant assign a List<string> to the Unsubscribe property which is an ArrayOfString - even though it inherits from List. In fact I cant seem to find ANY way to assign it without extra statements.
I've tried the following :
new ArrayOfString(unsubscribeFrom.ToList()) - this constructor doesn't exist :-(
changing the type of the array used by the code generator - doesn't work - it always gives me ArrayOfString (!?)
try to cast List<string> to ArrayOfString - fails with 'unable to cast', even though it compiles just fine
create new ArrayOfString() and then AddRange(unsubscribeFrom.ToList()) - works, but I cant do it all in one statement
create a conversion function ToArrayOfString(List<string>), which works but isn't as clean as I want.
Its only doing this for string, which is annoying.
Am i missing something? Is there a way to tell it not to generate ArrayOfString - or some other trick to assign it ?
Any .NET object that implements a method named "Add" can be initialized just like arrays or dictionaries.
As ArrayOfString does implement an "Add" method, you can initialize it like this:
var a = new ArrayOfString { "string one", "string two" };
But, if you really want to initialize it based on another collection, you can write a extension method for that:
public static class U
{
public static T To<T>(this IEnumerable<string> strings)
where T : IList<string>, new()
{
var newList = new T();
foreach (var s in strings)
newList.Add(s);
return newList;
}
}
Usage:
client.UpdateMailingList(new UpdateMailingListMsgIn()
{
Email = model.Email,
Name = model.Name,
Source = Request.Url.ToString(),
Subscribe = subscribeTo.ToList(),
Unsubscribe = unsubscribeFrom.To<ArrayOfString>()
});
I prefer not to return generic types across a service boundary in the first place. Instead return Unsubscribe as a string[], and SubscriptionInfo as SubscriptionInfo[]. If necessary, an array can easily be converted to a generic list on the client, as follows:
Unsubscribe = new List<string>(unsubscribeFrom);
Subscribe = new List<SubscriptionInfo>(subscribeTo);
Too late but can help people in the future...
Use the svcutil and explicitly inform the command line util that you want the proxy class to be serialized by the XmlSerializer and not the DataContractSerializer (default). Here's the sample:
svcutil /out:c:\Path\Proxy.cs /config:c:\Path\Proxy.config /async /serializer:XmlSerializer /namespace:*,YourNamespace http://www.domain.com/service/serviceURL.asmx
Note that the web service is an ASP.NET web service ok?!
If you are using VS 2008 to consume service then there is an easy solution.
Click on the "Advanced..." button on the proxy dialog that is displayed when you add a Service Reference. In the Collection Type drop down you can select System.Generic.List. The methods returning List should now work properly.
(Hope this is what you were asking for, I'm a little tired and the question was a tad difficult for me to read.)