I have few custom annotations defined on fields of an object like:
public class Person{
#Accountname
String email;
}
Implementation class of #Accountname:
#Autowired ValidationService service;
#Autowired ClientSession clientSession;
#Override
public boolean isValid(final String email, final ConstraintValidatorContext ctx) {
if(!service.isAccountValid(email, clientSession)){
return false;
}
}
I am trying to write junits for these annotations.
#Test
public void validEmailTest()
{
person.setEmail("abc#xyz.com");
Set<ConstraintViolation<Person>> violations = validatorInstance.getValidator().validateProperty(person, "email");
Assert.assertEquals(1, violations.size());
}
But its throwing this error when I execute the test:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.clientSession': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:343)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:34)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.getTarget(CglibAopProxy.java:663)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:614)
at org.hibernate.validator.internal.engine.ConstraintTree.validateSingleConstraint(ConstraintTree.java:308)
... 45 more
Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
at org.springframework.web.context.request.SessionScope.get(SessionScope.java:90)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:329)
... 54 more
Any idea on how to write junits if a validator class has a dependency on services like session etc.?
This should be tested separately (units).
The real logic that validates is in your ValidationService, so test it there, in AccountnameValidator test only the logic that is in there, injecting your dependencies:
#Mock ValidationService service;
#Mock ClientSession clientSession;
#InjectMocks AccountnameValidator av = new AccountnameValidator()
//initialize mocks
//example test
when(service.isAccountValid(email, clientSession)).thenReturn(true);
boolean result = av.isValid(email, ctx);
assertTrue(result);
And finally if you want you can validate presence of the annotation in Person class on email field using reflection.
Related
I have a #SessionScoped bean (CDI) that I would like to access and update from a EJB #Asynchronous method. If I pass a reference to a member variable in the bean via the #Asynchronous method's parameters and work with it, assuming the object being passed in is made thread safe, is there any other issues I should be aware of?
Is there any different to be aware if a #ViewScoped bean is used instead?
The only one I could think of would be if the CDI Session Bean timed out however that shouldn't be an issue because the object would be retained as the #Asynchronous method still has a reference to it.
I'm trying to pass off a long running task so as not to hold up the user clicking on a button but still update the session model with the result of the job so the user can see the outcome in a "job viewer" type interface.
Never access frontend classes from backend classes.
Just pass a callback to the EJB method.
#Asynchronous
public void asyncDoSomething(SomeInput input, Consumer<SomeResult> callback) {
SomeResult result = doSomethingWith(input);
callback.accept(result);
}
public void yourSessionScopedBeanMethod() {
yourEjb.asyncDoSomething(input, this::setResult);
}
public void setResult(SomeResult result) {
this.result = result;
}
I have a Flink Job reading events from a Kafka queue then calling another service if certain conditions are met.
I wanted to use Retrofit2 to call the REST endpoint of that service but I get a is not Serializable Exception. I have several Flat Maps connected to each other (in series) then calling the service happens in the last FlatMap. The exception I get:
Exception in thread "main"
org.apache.flink.api.common.InvalidProgramException: The
implementation of the RichFlatMapFunction is not serializable. The
object probably contains or references non serializable fields.
...
Caused by: java.io.NotSerializableException: retrofit2.Retrofit$1
...
The way I am initializing retrofit:
RetrofitClient.getClient(BASE_URL).create(NotificationService.class);
And the NotificationService interface
public interface NotificationService {
#PUT("/test")
Call<String> putNotification(#Body Notification notification);
}
The RetrofitClient class
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String baseUrl) {
if (retrofit == null) {
retrofit = new Retrofit.Builder().baseUrl(baseUrl).addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
Put your Notification class code for more details, but looks like this answer helps
java.io.NotSerializableException with "$1" after class
My web api looks like:
[Route("api/[controller]")]
public class ValuesController : Controller
{
private readonly ApplicationDbContext _context;
public ValuesController(ApplicationDbContext context)
{
_context = context;
}
[HttpGet]
public string Get()
{
// get random user
var user = _context.Users.SingleOrDefault();
return user?.Email ?? "";
}
}
Trying to call it via jquery:
$.get('/api/values', function (email) {
console.log(email)
})
I've 2 questions:
1/. Why didn't console.log(email) work although I was getting the response successful?
There was nothing in the Console tab.
2/. When I made a request to server (/api/values), the breakpoint had been caught:
My question: where had ValuesController been called within context? I'd sent a request from client, then the constructor was hit (I'm sure that I didn't send something like ApplicationDbContext from client to server :v)
UPDATE: By changing $.get('/api/values', {}, function (email) {} to $.get('/api/values', function (email) {}. I've fixed the first problem. It's my bad. Sorry about that.
Shorter Answer
My question: where had ValuesController been called within context? I'd sent a request from client, then the constructor was hit.
The HTTP Request arrived. ASP.NET MVC Routing told the application to use the ValuesController to handle the request. The application constructed the ValuesController, supplying an instance of ApplicationDbContext via dependency injection.
Longer Answer
The Startup.Configure method is used to specify how the ASP.NET application will respond to individual HTTP requests. Since you are using Web API, you have configured app.UseMvc(). Result: when an HTTP Request arrives, MVC Routing tells the application to use the appropriate controller.
The Startup.ConfigureServices method is used to specify services that are available via dependency injection. Since you are injecting an ApplicationDbContext into your constructor, you have configured services.AddDbContext<ApplicationDbContext>(). Result: when the application constructs a ValuesController, ASP.NET Dependency Injection will provide an instance of the ApplicationDbContext.
I have set up Ninject to work with SignalR (hosted on IIS) as described in the answer to this question: SignalR 2 Dependency Injection with Ninject.
This works in most cases, except when the client is disconnecting from the hub the HttpContext.Current variable is null and thus Ninject can't inject the value and throws an exception.
I've read up on the issue and found out that most people recommend that the current HttpContext should be retrieved from IRequest.GetHttpContext() (which is accessible from the hubs context). Sadly this doesn't help when trying to inject the value (I could pass on the context from the hub, but that would defeat the purpose of having dependency injection).
Code example (some parts removed for brevity):
public class TestHub : Hub
{
public TestHub(ITestService testService)
{
TestService = testService;
}
// When the disconnection request is issued, a ArgumentNullException
// for the HttpContext construction is thrown
public override Task OnDisconnected(bool stopCalled)
{
TestService.DoSomething();
}
}
public class TestService : ITestService
{
public TestService(HttpContextBase httpContext)
{
HttpContext = httpContext;
}
public void DoSomething()
{
// Service uses some data from the httpContext
TestLogger.Log(HttpContext.User.Identity.Name);
}
}
Is there any way to inject HttpContextBase into services that are in turn injected into SignalR hubs without accessing HttpContext.Current?
In case the HttpContext is actually available at construction time, you could use the following binding:
kernel.Bind<HttpContextBase>()
.ToMethod(ctx => Context.Request.GetHttpContext())
.WhenAnyAncestorMatches(ctx => typeof(Hub).IsAssignableFrom(ctx.Plan.Type));
The When condition checks whether the HttpContextBase is injected into a Hub (or derived class) or into any dependency of a Hub.
In case the HttpContextBase is only ever injected when contstructing Hubs, you could also just leave out the When condition.
I have worked around the issue now, and thus this is not a solution to the problem, but an unclean way to mitigate it.
Since the missing HttpContext only happens on client disconnects, I have first of marked all my injected services as Lazy<T>, so they don't get resolved immediately, but only when they are accessed. After applying this change, the exceptions are thrown only when code in the SignalR OnDisconnected event of the hub is triggered. So I had to modify the code in that is executed in the OnDisconnected method to use (or pass in as parameter) the context retrieved directly from the hub. In my case not much code gets executed in there, but it could become a problem if more is required in the future.
The patch applied to the sample code from my question:
public class TestHub : Hub
{
public TestHub(Lazy<ITestService> testService)
{
TestService = testService;
}
public override Task OnDisconnected(bool stopCalled)
{
DoSomethingThatInvolvesHttpContext(Context.Request.GetHttpContext());
}
}
So I already learnt that integration of spring and jax-ws is not an easy thing.
I want to inject a spring bean into jax-ws service, but for some reason I get an exception during the deployment:
Exception while loading the app : java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: java.lang.IllegalArgumentException: javax.servlet.ServletException: com.sun.enterprise.container.common.spi.util.InjectionException: Error creating managed object for class: class org.springframework.web.context.ContextLoaderListener|#]
this is my jax-ws configuration:
<wss:binding url="/ws/users">
<wss:service>
<ws:service bean="#usersWs"/>
</wss:service>
</wss:binding>
<bean id="usersWs" class="love.service.endpoint.implementations.UserServiceImpl" />
And this is my service:
#WebService
public class UserServiceImpl implements UserService{
#EJB
private DBManager dbmanager;
#Override
#WebMethod
public boolean addUser(String name, String password, String email) {
return false;
}
#Override
#WebMethod
public boolean isUsernameAvailable(String username) {
return dbmanager.isLoginAvailable(username);
}
#Override
#WebMethod
public boolean isEmailAvailable(String email) {
return dbmanager.isEmailAvailable(email);
}
}
and finally my bean configuration:
<bean id="dbmanager" class="love.commons.database.DBManager" scope="request">
<aop:scoped-proxy/>
</bean>
I also tried injecting the bean into some controllers and then it works perfectly well.
If I replace #EJB with #Autowired, the application starts, but the service still doesn't work. When I tried sending a message to it, my only response was the following:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
<faultcode>S:Server</faultcode>
<faultstring>Error creating bean with name 'scopedTarget.dbmanager': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.</faultstring>
</S:Fault>
</S:Body>
</S:Envelope>