#Inject CDI not working with JAX-RS - java

I'm trying to create a simple REST service with JAX-RS (Jersey), without using Spring. I want to have the typical structure of: Resource, that use a Service (typical interface with method findById, findAll...), and that Service injected in the Resource.
It seems that CDI automatically scans beans and injects them (having a empty beans.xml in the project) but... it doesn't work for me.
This is my Resource class:
#Path("users")
#ManagedBean
public class UserController {
#Inject
private UserService userService;
#GET()
#Path("/{id}")
#Produces(MediaType.APPLICATION_JSON)
public User getUserById(#PathParam("id") Long id) {
return userService.findById(id);
}
}
And this is my Service and its impl class (it´s a mock...):
public interface UserService {
User findById(Long id);
List<User> findAll();
User save(User user);
User update(User user);
void delete(Long id);
}
public class UserServiceMock implements UserService {
// omitted constants
#Override
public User findById(Long id) {
return new User()
.setId(id)
.setName(NAME_GANDALF)
.setPhone(PHONE_666554433)
.setType(TYPE_1)
.setBirthDate(LocalDate.parse(STRING_DATE_19110102));
}
#Override
public List<User> findAll() {
return Arrays.asList(
new User()
.setId(USER_ID_12)
.setName(NAME_GANDALF)
.setPhone(PHONE_666554433)
.setType(TYPE_1)
.setBirthDate(LocalDate.parse(STRING_DATE_19110102)),
new User()
.setId(USER_ID_140)
.setName(NAME_ARAGORN)
.setPhone(PHONE_661534411)
.setType(TYPE_1)
.setBirthDate(LocalDate.parse(STRING_DATE_19230716)),
new User()
.setId(USER_ID_453321)
.setName(NAME_FRODO)
.setPhone(PHONE_666222211)
.setType(TYPE_2)
.setBirthDate(LocalDate.parse(STRING_DATE_19511124))
);
}
#Override
public User save(User user) {
return user.setId(USER_ID_453321);
}
#Override
public User update(User user) {
return user;
}
#Override
public void delete(Long id) {
// delete user by id
}
}
And I'm using a "no web.xml" configuration, with this class:
#ApplicationPath("api")
public class RestApplication extends ResourceConfig {
}
The only workaround I found is to "register" the service in the RestApplication class:
#ApplicationPath("api")
public class RestApplication extends ResourceConfig {
public RestApplication() {
register(UserController.class);
register(new AbstractBinder() {
#Override
protected void configure() {
bind(new UserServiceMock()).to(UserService.class);
}
});
}
}
Is there another solution to this problem? I'd rather not to register all my services and other stuff in this class manually...
I tried with annotations like #Default, #Qualifier and more (in the service), and no one works...

Tomcat is a servlet container only. It's not a full Java EE enterprise stack, nor does it contain a CDI container. Apache TomEE, on the other hand, is Tomcat with EE capabilities.
Bauke Scholtz, the infamous BalusC, wrote an excellent blog on installing CDI on Tomcat. This might help you. Otherwise, an alternative approach will be to install Apache TomEE and run your application from there. After all, it's still Tomcat anyway.

Related

Spring RabbitMQ: implement additional validations without custom annotations

In a Spring RabbitMQ project I am looking for a way to programmatically validate an object that has JSR303 annotations (like #NotNull, #Size, etc) while at the same time requires some custom validation logic. I would normally use a ConstraintValidator in combination with a custom Annotation, but the use of custom Annotations is not an option in this case.
I have the following (simplified) class, which is generated by Swagger and therefore cannot be edited:
#ApiModel(description="User")
public class User {
private String name;
#NotNull
#Size(min = 1, max = 6)
public String getName() {
return this.name;
}
...
}
The additional validation logic is encapsulated in a validator:
#Component
public class UserValidator implements org.springframework.validation.Validator {
#Override
public boolean supports(Class<?> aClass) {
return User.class.equals(aClass);
}
#Override
public void validate(Object o, Errors errors) {
User user = (User) o;
...
if(!valid) {
errors.reject("some rejection");
}
}
}
The service in which the validation occurs:
#Service
#RequiredArgsConstructor
public class SomeService {
private final javax.validation.Validator validator; // might as well be org.springframework.validation.Validator if that works better
public void someMethod(User user) {
if (!validator.validate(user).isEmpty()) {
// handle invalid user
}
...
}
}
However, the UserValidator is not being invoked. Is there some way to make Spring aware of the UserValidator? I have read some topics on using an InitBinder, however as this is not a web MVC project but a rabbitMQ project I'm not sure whether this can be used.
It is not clear from your description how this is relevant to Spring AMQP, but if you want to use a validator on the listener method level, you should configure it respectively:
#Configuration
#EnableRabbit
public class Config implements RabbitListenerConfigurer {
...
#Override
public void configureRabbitListeners(RabbitListenerEndpointRegistrar registrar) {
registrar.setValidator(new MyValidator());
}
}
See docs for more info: https://docs.spring.io/spring-amqp/docs/current/reference/html/#rabbit-validation

How to make Jersey #RolesAllowed with #Stateless work?

I'm not sure whether this is possible or not but I'm trying to setup a EJB + JAX-RS (Jersey) test project and use the #RolesAllowed annotation.
I'm currently getting the following error logs:
Warning: WEB9102: Web Login Failed: com.sun.enterprise.security.auth.login.common.LoginException: Login failed: Security Exception
Severe: ejb.stateless_ejbcreate_exception
Warning: A system exception occurred during an invocation on EJB TestSB, method: public java.util.List rest.sb.TestSB.findAll()
Warning: javax.ejb.EJBException: javax.ejb.EJBException: javax.ejb.CreateException: Could not create stateless EJB
Relevant classes:
ApplicationConfig.java
#ApplicationPath("rest")
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
packages("rest");
register(RolesAllowedDynamicFeature.class);
}
}
TestSBFacade.java
#Local
public interface TestSBFacade {
public List<Test> findAll();
}
TestSB.java
#Stateless
#Path("secured/test")
public class TestSB implements TestSBFacade {
#DAO #Inject
private TestDAOFacade dao;
#Context
SecurityContext securityContext;
#Secured
#RolesAllowed({"READ"})
#Path("all")
#GET
#Produces(MediaType.APPLICATION_JSON)
#Override
public List<Test> findAll() {
//this works without the #RolesAllowed so it is a possible workaroud for now.
System.out.println(securityContext.isUserInRole("READ")); //output: true
return dao.findAll();
}
}
AuthFilter.java
#Provider
#Secured //NameBinding
#Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
String token = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
try {
verifyToken();
createSecurityContext();
} catch (Exception e) {
Logger.getLogger(AuthenticationFilter.class.getName()).log(Level.SEVERE, null, "Invalid or Expired JWT");
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
}
}
}
My SecurityContext is set and working, the #RolesAllowed seems to be to problem since I get no errors if I remove it and a JSON is properly returned to the front-end. Keeping the #RolesAllowed results in the errors mentioned at the start.
However I'd like to use the handy annotation instead of embedding every method inside isUserInRole IF Statements. Any help and insights are much appreciated.
So apparently due to both EJB and JAX-RS implementations using#RolesAllowed they don't do well together. So I decided to create my own Annotation instead and register my own DynamicFeature in the ApplicationConfig.java.
Authorized.java
#Documented
#Retention(RUNTIME)
#Target({TYPE, METHOD})
public #interface Authorized {
public String[] value() default "";
}
AuthorizationDynamicFeature.java
public class AuthorizationDynamicFeature implements DynamicFeature {
#Override
public void configure(final ResourceInfo resourceInfo, final FeatureContext featureContext) {
Authorized auth = new AnnotatedMethod(resourceInfo.getResourceMethod()).getAnnotation(Authorized.class);
if (auth != null) {
featureContext.register(new AuthorizationRequestFilter(auth.value()));
}
}
#Priority(Priorities.AUTHORIZATION)
private static class AuthorizationRequestFilter implements ContainerRequestFilter {
private final String[] roles;
AuthorizationRequestFilter() {
this.roles = null;
}
AuthorizationRequestFilter(final String[] roles) {
this.roles = roles;
}
#Override
public void filter(final ContainerRequestContext requestContext) throws IOException {
if (!this.roles[0].isEmpty()) {
for (final String role : this.roles) {
if (requestContext.getSecurityContext().isUserInRole(role)) {
return;
}
}
throw new ForbiddenException(LocalizationMessages.USER_NOT_AUTHORIZED());
}
}
}
}
Huge thanks to #PaulSamsotha for leading me to a more suitable solution.

404 Not found - when I try to access the url for a Spring and Hibernate application (Rest Service based without front-end)

everyone.
I am trying to create a Spring application, using Hibernate.
The application have not been created with front-end part, only the entities, services, dao and rest controllers.
When I run the application (I am using Eclipse as IDE and WebSphere - I need to use this configuration) and try to access the URL of the app, I receive 404 Not found.
I also ran the application into debug mode with a breakpoint before the returning ResponseEntity of the request and with a print statement for the entity that I am trying to access (a user, for example). Whenever I do this, I try to access the URL, I receive in console application the message that I wanted to print and the entity from the DB. Also, every layer of the application is created in a Maven module.
Any ideas what I am doing wrong?
This is my UserController class:
import x.stm.entity.User;
import x.stm.service.UserService;
#Controller
public class UserController {
#Autowired
private UserService userService;
/*---Add new user---*/
#RequestMapping(path={"/user"}, method = RequestMethod.POST)
public ResponseEntity<?> save(#RequestBody User user) {
userService.addUser(user);
return ResponseEntity.ok().body("User was added" );
}
// ---Get a user by id---
#RequestMapping(path={"/user/{id}"}, method = RequestMethod.GET)
public ResponseEntity<User> get(#PathVariable("id") int id) {
User user = userService.getUserById(id);
System.out.println(user);
return ResponseEntity.ok().body(user);
}
}
And this is application configuration and initializer:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {
"x.stm.rs.controller" })
public class RestApplicationConfig extends WebMvcConfigurerAdapter {
//
}
public class RestApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {HibernateConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { RestApplicationConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}

#DAO and #Service beans clarification

I have a basic question. I've been reading through some tutorials about spring and hibernate integration and in most of them there are DAO and Service layers like below:
public interface TeamDAO {
public void addTeam(Team team);
public void updateTeam(Team team);
public Team getTeam(int id);
public void deleteTeam(int id);
public List<Team> getTeams();
}
Then the implementation of the DAO is provided using the SessionFactory. For example:
#Repository
public class TeamDAOImpl implements TeamDAO {
#Autowired
private SessionFactory sessionFactory;
//Implementation follows..
}
And then there's another service interface the same as the DAO interface like below:
public interface TeamService {
public void addTeam(Team team);
public void updateTeam(Team team);
public Team getTeam(int id);
public void deleteTeam(int id);
public List<Team> getTeams();
}
And the service implementation:
#Service
#Transactional
public class TeamServiceImpl implements TeamService {
//HERE IS MY QUESTION
#Autowired
private TeamDAO teamDAO;
//implementation follows
}
In the service implementation above where I marked "here is my question" I see that we inject only the interface TeamDAO which doesn't have the implementation of the TeamDAOImpl class. So how does the interface and its implementations get injected together in the service layer provided we only inject the interface TeamDAO and not TeamDAOImpl?
When you use #Autowired on an interface, Spring searches a bean instance whose class implements that interface. If it doesn't find any such bean, it fails. If it finds more than one class that implement the interface, it fails. Please refer to Spring #Autowired documentation for further details.
Spring injects TeamDAOImpl because it gets register as spring bean when you mark it as #Repository

Spring/Hibernate App only working without #Transactional

I got another problem when working on my current Spring and Hibernate application. I have built my DAO interfaces/classes, as well as my Service interfaces/classes and of course the Entities.
Everything is being deployed well but as soon as I add the #Transactional annotation to my XXXServiceImpl classes, I get the following exception during deployment (tested on Glassfish AND Tomcat):
Caused by: java.lang.IllegalStateException: Cannot convert value of type [com.sun.proxy.$Proxy25 implementing net.dreamcode.bleevle.persistence.service.IntranetService,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [net.dreamcode.bleevle.persistence.service.impl.IntranetServiceImpl] for property 'intranetService': no matching editors or conversion strategy found
Of course, I tried to find something about that and I guess it's basically because interface and class are not matching when adding the annotation. But I also tried adding the annotation on my interfaces, which didn't help along to solve the problem, producing the same error as stated above.
Here's some example code from my project (BasicService, UserService and UserServiceImpl):
BasicService (Interface):
public interface BasicService<T> {
T findById(String id);
void create(T entity);
void delete(T entity);
void update(T entity);
}
UserService (Interface):
import net.dreamcode.bleevle.data.User;
public interface UserService extends BasicService<User> {
User findByName(String name);
}
UserServiceImpl (Class):
public class UserServiceImpl implements UserService {
#Autowired
UserDao userDao;
#Override
public User findByName(String name) {
return userDao.findByName(name);
}
#Override
public User findById(String id) {
return userDao.findById(id);
}
#Override
public void create(User entity) {
userDao.create(entity);
}
#Override
public void delete(User entity) {
userDao.delete(entity);
}
#Override
public void update(User entity) {
userDao.update(entity);
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
Is there a specific thing to do when working with this kind of pattern (I guess it's some kind of design pattern with Service and Dao stuff)?
Any kind of help is greatly appreciated. Thanks in advance!
You have a property
#Autowired private IntranetServiceImpl intranetService;
(or an equivalent thereof, such as an annotated constructor parameter or a setter) whose type is the implementation type of your service. This is wrong: you should always use the interface type for your properties.
The reason why it fails as soon, but no earlier than, you annotate with #Transactional is that this annotation causes Spring to create a dynamic proxy of your interface where otherwise there would be the naked implementation class instance. This dynamic proxy fails to be downcast into your implemantation type, but would be successfully cast into the interface type.

Categories

Resources