Quarkus inject RequestInfo in bean - jax-rs

I'm able to inject RequesInfo instances in Jaxrs resources by using the #Context annotation.
What I'm trying to do is to inject the same interface but in a bean that is not a Jaxrs resource. This fails with a NPE when accessing the variable.
#RequestScoped
public class Service {
#Context
private ResourceInfo resourceInfo;
public Service() {
}
public ResourceInfo getResourceInfo() {
return resourceInfo;
}
}
#ApplicationScoped
#Path("/hello")
public class GreetingResource {
private final Service service;
#Inject
public GreetingResource(Service service) {
this.service = service;
}
#GET
#Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "Hello RESTEasy";
}
#GET
#Path("service")
#Produces(MediaType.TEXT_PLAIN)
public String resourceInfoService() {
return service.getResourceInfo().getResourceClass().getName();
}
}
I have looked at Jaxrs spec but I did saw any clear evidence saying that this should be supported or not. I've used this technique in other spec implementations like Payara, but in Quarkus it fails.

Related

Why i send error "WFLYEJB0054: Failed to marshal EJB parameters" with JAX-RS?

I have projects with two modules :EJB and JAX-RS
JAX-RS
Interface
package com.EJB;
#Remote
public interface TeamEJB {
public Response createTeam(String nameTeam, Set<Integer> idsHuman);
public Response test(String nameServer);
public Response changeMood(int id_team);
public Response getTeams();
}
Main controller
package com;
public class TeamServlet implements Serializable {
TeamEJB ejb= (TeamEJB) FactoriesKt.getFromEJBPool("ejb:/two/TeamEJBImpl!com.EJB.TeamEJB");
#GET
#Path("/test")
public Response test() {
String nameServer="OK 1 ";
return ejb.test(nameServer);
}
}
Modules EJB
interface
package com.EJB;
public interface TeamEJB {
public Response createTeam(String nameTeam, Set<Integer> idsHuman);
public Response test(String nameServer);
public Response changeMood(int id_team);
public Response getTeams();
}
Ejb-bean
package com.EJB;
#Stateless #Remote(TeamEJB.class)
public class TeamEJBImpl implements TeamEJB, Serializable {
private static final long serialVersionUID = 1L;
#Override
public Response test(String nameServer) {
return Response.ok().entity(nameServer).build();
}
}
But i get error
WFLYEJB0054: Failed to marshal EJB parameters
java.io.NotSerializableException: org.jboss.resteasy.specimpl.BuiltResponse

how to inject depencies to constructor controller

I'm trying to configure an API which a controller use depency injection to inject an object to this controller
public class BaseAPIController
{
private readonly Repository _repository;
public BaseAPIController(Repository repository)
{
_repository = repository;
}
// some common functions and properties are declared here
}
public class AccountController : BaseAPIController
{
public AccountController(Repository repository) : base(repository)
{ }
}
but it throws an exception that tells "Some services are not able to be constructed..."
I tried a solution that use ILogger<Repository> instead of using Repository instance then this runs properly
public class AccountController : BaseAPIController
{
public AccountController(ILogger<Repository> repository) : base(repository)
{ }
}
the registion service in startup.cs code
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddScoped<IRepository, Repository>();
services.AddSingleton<WeatherForecastController, WeatherForecastController>();
}
and the declaration of Repository class
public interface IRepository
{
void DoSomething1();
void DoSomething2();
void DoSomething3();
}
public class Repository : IRepository
{
public readonly string _connectionString;
public Repository(string connectionString)
{
_connectionString = connectionString;
}
public void DoSomething1() {}
public void DoSomething2() {}
public void DoSomething3() {}
}
How can I archive the configuration above without using ILogger instance
Thanks
This is the registration you made:
services.AddScoped<IRepository, Repository>();
But this is AccountController's constructor:
AccountController(Repository repository)
Notice how AccountController is depending on the concrete type Repository; not on the IRepository interface. Because of this registration, Repository can only be resolved through its IRepository interface, but not directly (that's by MS.DI's design).
The solution, therefore, is to change AccountController's constructor to the following:
AccountController(IRepository repository)
The issue is that DI cannot create an instance of Repository because there is no parameterless constructor. Take a look at the docs for injecting settings rather than requiring a string in the constructor. Add your connection string to your appsettings.json file:
{
"AppSettings": {
"ConnectionString": "<connection_string>"
}
}
In ConfigureServices register your settings class:
public class AppSettings
{
public string ConnectionString;
}
public void ConfigureServices(IServiceCollection services)
{
services.Configure<AppSettings>(Configuration.GetSection(AppSettings));
...
}
Then your Repository class constructor would look like this:
public Repository(IOptions<PositionOptions> options)
{
_connectionString = options.Value.ConnectionString;
}
You also need to inject the interface IRepository, not the concrete class into your controller.
public class BaseAPIController
{
private readonly IRepository _repository;
public BaseAPIController(IRepository repository)
{
_repository = repository;
}
// some common functions and properties are declared here
}

Using and extending JOOQ generated DAOs with injected DataSource?

I'm new to JOOQ... The following code seems to work in WildFly 22 but I'm not sure if that is the best way to do things. What is the preferred way to inject WF DataSource to JOOQ DAOs (my extended ones)? Is there a way to avoid doing the ".get()." in the service below and just leave #Resource(...) etc. connection related for the MyCompanyDAO to handle internally?
In other words: companyDAO.get().fetchOneById(id) vs. companyDAO.fetchOneById(id)
#Stateless
public class CompanyService extends DefaultCompanyService {
#Inject
private MyCompanyDAO companyDAO;
public Company find(Integer id) {
return companyDAO.get().fetchOneById(id);
}
}
#Stateless
public class MyCompanyDAO extends CompanyDao {
#Inject
private MyConnectionProvider cp;
public CompanyDAO get() { // since cannot use #Resource in dao constructor
this.configuration().set(cp).set(SQLDialect.POSTGRES);
return this;
}
// custom code here
}
public class CompanyDao extends DAOImpl<CompanyRecord, tables.pojos.Company, Integer> {
// jooq generated code here
}
#Stateless
#LocalBean
public class MyConnectionProvider implements ConnectionProvider {
#Resource(lookup = "java:/MyDS")
private DataSource dataSource;
#Override
public Connection acquire() throws DataAccessException {
try {
return dataSource.getConnection();
} catch (SQLException e) {
throw new DataAccessException("Could not acquire connection.", e);
}
}
#Override
public void release(Connection connection) throws DataAccessException {
try {
connection.close();
} catch (SQLException e) {
throw new DataAccessException("Could not release connection.", e);
}
}
}
Put initialization logic of MyCompanyDAO inside a #PostConstruct method.
#PostConstruct
public void init() {
this.configuration().set(cp).set(SQLDialect.POSTGRES);
}
This way, you don't need to call get:
#Inject
private MyCompanyDAO companyDAO;
public Company find(Integer id) {
return companyDAO.fetchOneById(id);
}
How about using constructor injection instead? The generated DAO classes offer a constructor that accepts a Configuration precisely for that:
#Stateless
public class MyCompanyDAO extends CompanyDao {
#Inject
public MyCompanyDAO (Configuration configuration) {
super(configuration);
}
}
If for some reason you cannot inject the entire configuration (which I'd recommend), you could still inject the ConnectionProvider:
#Stateless
public class MyCompanyDAO extends CompanyDao {
#Inject
public MyCompanyDAO (MyConnectionProvider cp) {
super(DSL.using(cp, SQLDialect.POSTGRES));
}
}

How to mock protected final method of base class using jmockit

public class Dao1 extends GenericDao{
}
public class Dao2 extends Dao1{
}
public class GenericDao(){
protected final Session getCurrentSession() {
LOG.debug("getting current Session");
return sessionFactory.getCurrentSession();
}
}
I am testing methods in Dao2 and wants to mock getCurrentSession method from GenericDao.
I tried to mock it using
new MockUp<GenericDao>() {
#Mock
protected Session getCurrentSession() {
return session;
}
};
}
I am getting following exception at line new MockUp<GenericDao>():
java.lang.NoSuchMethodError: mockit.internal.startup.AgentLoader: method <init>()V not found
at mockit.internal.startup.Startup.verifyInitialization(Startup.java:172)
at mockit.MockUp.<clinit>(MockUp.java:94)

Spring TestRestTemplate authentication

I am trying to build Spring Boot test to test rest API, so that I can get Principal from the request and use that to identify the user.
Server returns
{"timestamp":1502014507361,"status":403,"error":"Forbidden","message":"Access
Denied","path":"/hello"}
What am I missing here?
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class RestTemplateTest {
#Autowired
TestRestTemplate testRestTemplate;
#Test
public void testit() {
testRestTemplate.withBasicAuth("user", "password");
String responsePayload = testRestTemplate.getForObject("/hello", String.class);
}
#RestController
public class GreetingController {
#RequestMapping("/hello")
public String heipat(Principal principal) {
String string = "hello there";
return string;
}
#Configuration
#EnableWebSecurity
static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeRequests().anyRequest().hasRole("USER");
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
You need to be authenticated first. like requesting a /login API.
Also you need to make the login API accessible by everyone by doing this:
http.csrf().disable().authorizeRequests()
.antMatchers("/login").permitAll()
When you includes WebSecurityConfig you will have basic usernamerAndPassowrd authentication.