quick help if you can. Trying to implement calls to third party native function that accepts an object that has to implement a certain interface with a callback function. How exactly would you create an object like that on the Nativescript side and pass it to that native function?
Java example:
public class Logger {
public static void setListener(LogListener listener) {
// native code
}
}
public interface LogListener {
void onMessageLogged(LogMessage message);
}
So you want to pass in a LogListener to setListener?
In TypeScript that would be:
const myLogListener = new change.packagename.LogListener({
onMessageLogged: message => {
console.log(message);
}
});
logger.setListener(myLogListener);
Related
I was using WebApplicationFactory for integration tests, but then I wanted to use DI for my test classes for my services and repos and Xunit was not a big fan of interfaces and ctors, so I wanted to put all my services and dependencies in WebApplicationFactory which I think is the appropriate way but the thing is my main API project is a fully functioning API with auth (such as MSAL and branches, users that require internet connection). So, every time I call a validator I get 401
public class SqliteTests : IClassFixture<ApiWebAppFactory>
{
private readonly IValidator<Contact> _validator;
public SqliteTests(ApiWebAppFactory factory)
{
var scope = factory.Services.GetRequiredService<IServiceScopeFactory>().CreateScope();
//401 unauthorized here
_validator = scope.ServiceProvider.GetRequiredService<IValidator<Contact>>();
}
[Fact]
public async void MyTest()
{
//...
}
}
I usually fix this kind of problem by returning new objects from the IServiceProvider's ctor
like this:
public class ApiWebAppFactory :
WebApplicationFactory<Actual.API.Mappings.MappingProfiles>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
//...
services.AddScoped<IRepository<Contact>, Repository<Contact>>
(x =>
{
return new Repository<Contact>(x.GetRequiredService<SqliteMockDbContext>());
});
//...
But I couldn't find a way to do the same thing with the FluentValidation; validation and ValidatorFactory(some of our services use IValidatorFactory).
They always seem to call to the main API project's Program.cs and its all dependencies which ends up in 401 Unauthorized.
This code might look ugly but I also have the same issue with my IService which expects an IValidatorFactory;
services.AddScoped<IService<Contact, IRepository<Contact>,
BaseResponse<Contact>, BaseResponseRange<IEnumerable<BaseResponse<Contact>>,
Contact>>, Service<Contact, IRepository<Contact>, BaseResponse<Contact>,
BaseResponseRange<IEnumerable<BaseResponse<Contact>>, Contact>>>(
x =>
{
var repo = x.GetRequiredService<IRepository<Contact>>();
var uow = x.GetRequiredService<IUnitOfWork>();
return new Service<Contact, IRepository<Contact>, BaseResponse<Contact>,
BaseResponseRange<IEnumerable<BaseResponse<Contact>>, Contact>>(
repo,uow, //this = new ServiceProviderValidatorFactory(x)
);
}
In Java, I have the documentation for the following code:
import com.creator.creatorandroidsdk.terminal.DeviceSelectionListener
import com.creator.creatorandroidsdk.TerminalListManager;
public class ConfigPinPadActivity extends Activity implements DeviceSelectionListener {
TerminalListManager terminalListManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
terminalListManager = new TerminalListManager(this,getApplicationContext());
terminalListManager.startTerminalsDiscovery();
}
//...
}
Where this is sent to a class method as a reference to the instance of the implementation itself:
terminalListManager = new TerminalListManager(this,getApplicationContext());
I've tryied to replicate the code in NativeScript, but the reference doesn't work:
const { DeviceSelectionListener } = com.creator.creatorandroidsdk.terminal
const { TerminalListManager } = com.creator.creatorandroidsdk
const superProto = androidx.appcompat.app.AppCompatActivity.prototype
androidx.appcompat.app.AppCompatActivity.extend(
'com.company.configPinPadActivity',
{
interfaces: [DeviceSelectionListener],
terminalListManager: {},
onCreate: function (savedInstanceState) {
console.log('OnCreated fired') // <- It works.
this.terminalListManager = new TerminalListManager(this, utilsModule.ad.getApplicationContext())
This particular error comes up.
JNI ERROR (app bug): attempt to pass an instance of com.company.configPinPadActivity as argument 1 to void com.creator.creatorandroidsdk.TerminalListManager.<init>(com.creator.creatorandroidsdk.terminal.DeviceSelectionListener, android.content.Context)
JNI DETECTED ERROR IN APPLICATION: bad arguments passed to void com.creator.creatorandroidsdk.TerminalListManager.<init>(com.creator.creatorandroidsdk.terminal.DeviceSelectionListener, android.content.Context) (see above for details)
I'm really trying to pass an instance of com.company.configPinPadActivity implementation to the new TerminalListManager, and since the com.company.configPinPadActivity implements a DeviceSelectionListener, I cannot understand why this isn't working.
How can reference the instance of the implementation from within the implementation itself?
Looks like you are confusing TerminalListManager to being an interface. You cannot instantiate interfaces (new TerminalListManager), only implementations of such interfaces.
Would help if you add the source of TerminalListManager. If you are trying to pass 'this' to the TerminalListManager constructor, you need to have the the type of first parameter ConfigPinPadActivity (or Activity if you plan to re-use the TerminalListManager) or of type DeviceSelectionListener.
In Startup.cs i have a extremely simple Map
app.Map("/Home",x=>x.UseMiddlewareLogic1() );
My full code of Configure looks as shown below
public void Configure(IApplicationBuilder app)
{
app.Map("/Home",x=>x.UseMiddlewareLogic1() );
//app.UseMiddlewareLogic1();
//app.UseMiddlewareLogic2();
app.Run(async context =>
Logic3(context));
}
Logic 3 is just a response write as shown below
public async Task Logic3(HttpContext obj)
{
await obj.Response.WriteAsync("Logic 3\n");
}
The above code shows 404 not found.
The middleware logic class is the standard class which comes in the visual studio template. I am using VS 2017.
public class MiddlewareLogic1
{
private readonly RequestDelegate _next;
public MiddlewareLogic1(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
await httpContext.Response.WriteAsync("This is logic123 \n");
await _next(httpContext);
}
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class MiddlewareLogic1Extensions
{
public static IApplicationBuilder UseMiddlewareLogic1(this IApplicationBuilder builder)
{
return builder.UseMiddleware<MiddlewareLogic1>();
}
}
This is your problem: app.Map("/Home",x=>x.UseMiddlewareLogic1() );.
If you are using app.Map, the framework will not execute middlewares outside Map branch (that are registered after app.Map - order of middleware is important). Instead, it will automatically terminate that. In other words, you never need use .Run inside .Map to terminate the pipeline.
And you get 404 as there is await _next(httpContext); in your MiddlewareLogic1 middleware used in Map, but there are no other pipelines registered in this Map branch.
If you remove await _next(httpContext); you will see in response "This is logic123 instead of 404.
Update: both .Map and .MapThen have the same terminating behavior. As a solution, you may consider to
- replace .Map to .Use and do query comparing login internally.
- Or register a separate chain of middlewares in .app.Map.
How can I use two action compositions in Play Framework 2.4 (in Java)?
Suppose that, to avoid code duplication, I've got two actions to use :Auth and LogData.
How can I use both in an action composition?
This won't compile, causing a duplicate annotation error:
# play.PlayExceptions$CompilationException: Compilation error[error:
duplicate annotation]
#play.db.jpa.Transactional()
#With(Auth.class)
#With(LogData.class)
public static Result callForumTeacher(String random, Long gameId){
//Action code
return ok(Json.toJson("data"));
}
This is a skeleton on how Auth and LogData are implemented:
public class CheckPausedGame extends Action.Simple {
#Override
public F.Promise<Result> call(Http.Context context) throws Throwable {
if (checkCondition(context)) {
return delegate.call(context);
} else {
F.Promise<Result> promise = F.Promise.promise(new F.Function0<Result>() {
#Override
public Result apply() throws Throwable {
return redirect("/paused");
}
});
return promise;
}
}
}
This only a skeleton omitting some methods not useful for this question.
While the documentation doesn't seem to clearly state this (at least I haven't found it anywhere), the intended way to use #With in cases like this is to pass all Actions at once (With takes an array)
Your code becomes
#play.db.jpa.Transactional()
#With(value = {Auth.class, LogData.class})
public static Result callForumTeacher(String random, Long gameId){
//Action code
return ok(Json.toJson("data"));
}
See the api doc
I want to use Reactor something like that:
reactor.notify(new CreatedEvent<A>(a));
reactor.notify(new CreatedEvent<B>(b));
Where my event is simply:
public class CreatedEvent<E> extends Event<E> {
public CreatedEvent(E data) {
super(data);
}
}
And then consume those events like that:
reactor.on(new Consumer<CreatedEvent<A>>() {
#Override
public void accept(CreatedEvent<A> t) {
/* do something with a */
}
});
reactor.on(new Consumer<CreatedEvent<B>>() {
#Override
public void accept(CreatedEvent<B> t) {
/* do something with b */
}
});
But I receive both events with both consumers.
If I use selectors it works, i.e.:
reactor.notify("created.a", Event.wrap(a));
reactor.on(Selectors.$("created.a"), new Consumer<Event<A>>() {
#Override
public void accept(Event<A> t) {
/* do something with a */
}
});
But using selectors I would have to write and maintain very much String.
Is it all about using selectors? Or can I somehow "select by parameterized class type"?
But I receive both events with both consumers.
Right. Because you send both events to the same reactor just to defaultKey.
And subscribe both consumers to the defaultSelector.
In this case it doesn't have value which types of Event you use: they all will be dispatched by default Selector strategy.
I think you need to use ClassSelector:
reactor.notify(a);
reactor.notify(b);
reactor.on(Selectors.T(A.class), new Consumer<Event<A>>() {});
reactor.on(Selectors.T(B.class), new Consumer<Event<B>>() {});
Of course, you have to type Selectors.T for each class-consumer, but it is more simpler then ObjectSelector and custom Event.
UPDATE
How to inject a custom consumer filter:
Reactors.reactor()
.eventFilter(new GenericResolverFilter())
.get()
And it's up to you how to resolve a generic argument from consumerKey Object and each Consumer from List<T> items. Anyway you should think here about some caching to allow to Reactor continue to be reactive.