How to initialize a object in a interface? - java

I have this MovieService.java:
#Service
public class MovieService implements MovieInterface {
#Autowired
private MovieRepository movieRepository;
#Autowired
private UserRepository userRepository;
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
JwtUser user = (JwtUser)authentication.getPrincipal();
User current_user = userRepository.findOne(user.getId());
#Override
public Movie createMovie(Movie movie) {
current_user.addMovie(movie);
userRepository.save(current_user);
return movie;
}
}
This is the error I'm getting when I'm compiling my code:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'movieController': Unsatisfied dependency expressed through field 'movieService'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'movieService' defined in file [C:\Users\alucardu\Documents\projects\movieseat\backend\target\classes\com\movieseat\services\MovieService.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.movieseat.services.MovieService]: Constructor threw exception; nested exception is java.lang.NullPointerException
This problem is resolved when I move the authentication, user and current_user properties into the createMovie method. But I want to use current_user in multiple methods so I would like to add it as a class member.
I also implement a MovieInterface:
package com.movieseat.interfaces;
// Java imports
import java.util.List;
import com.movieseat.model.security.User;
// Project imports
import com.movieseat.models.Movie;
import com.movieseat.security.JwtUser;
import org.springframework.security.core.Authentication;
public interface MovieInterface {
List<Movie> getAllmovies();
Movie createMovie(Movie movie);
void deleteMovie(Integer id);
}
So I thought maybe the code doesn't compile because the properties authentication, user and current_useraren't defined in the interface. Although I would expect a different error output for something like that. When I add the properties to the interface:
public interface MovieInterface {
Authentication authentication;
JwtUser user;
User current_user;
List<Movie> getAllmovies();
Movie createMovie(Movie movie);
void deleteMovie(Integer id);
}
I get the message:
the blank final field authentication may not have been initialized
the blank final field user may not have been initialized
the blank final field current_user may not have been initialized
This message makes sense since the interface expects the fields to be final. And these fields have no value. So my question is, can I mark a field not final in a interface? And if I have to initialize a value for the fields what do I need to use?
I know you initialize a field String name = "name"; But these properties are objects.
User current_user = {};
Cannot convert from Object[] to User

Your service is a bean, and especially it is a singleton. That means there is only one instance of this service in your application.
But it may be called by different users. So you have to get the current user in your createMovie method (you already named it current User!).
When you try to initialize these fields in a PostConstruct method, you won't have a SecurityContext and you won't have a principal. And if you keep the info about the current user in the service instance, then all calls would be made on behalf of this one user, no matter where they come from.
So the best thing is to create a method :
private getUser() {
Authentication authentication =
SecurityContextHolder.getContext().getAuthentication();
JwtUser user = (JwtUser)authentication.getPrincipal();
User current_user = userRepository.findOne(user.getId());
return current_user;
}
and call that from within your different methods.

Your class is a bean. This means, all #Autowired fields will be set from someone else (Spring or CDI). Question is WHEN?. You might have bean A with auto wired bean B as property and the other way around. You need to wait, until all properties have been auto wired. You try to use userRepository during object creation. That's too early. Spring has to create the Java object (no way around this), but will do the autowiring after that. But with dependency injection, you will get told when all properties have been set, if you annotate a method with #PostConstruct.
#PostConstruct
public void init(){
// it is safe now to use user repository, because it is not null anymore
}

Related

Spring: #RequestScope - annotated method does not get called

In the application I would like to create a request-scoped bean (annotated with #RequestScope) that would represent a user of the application (for authentication OAuth2 is used with the company's own authentication provider based off keycloak; the problem is that the Principal doesn't contain extra information about the permissions this particular user has and they have to be retrieved from another service, which is why I want to have this request-scoped bean that would retrieve fresh permissions on each request).
public class MyApplicationUser {
private final String name;
private final List<Permission> permissions;
/* all-arg constructor, getters */
}
#Configuration
public class UserConfiguration {
private final PermissionService permissionService;
/* constructor, etc */
#Bean
#RequestScope
public MyApplicationUser currentUser(#CurrentSecurityContext(expression = "authentication") OAuth2AuthenticationToken authenticationToken) {
/* call permissionService, map the result and the token details data to MyApplicationUser instance and return it*/
}
}
Although on each request a new instance of MyApplicationUser is created, it is not created by calling the currentUser method (it never gets called), but rather it seems that spring uses the provided constructor and supplies nulls as parameters, which is not what I want. How do I fix that?
P.S. the main class extends SpringBootServletInitializer

How to access Principal in controller methods without it declared as argument?

I added Spring Security on a Rest API with JWT authentication. Now I need to retrieve some data from the token in every controller method - be it either the username or other information.
Since almost all of my controller methods would need a Principal variable, is there a way to avoid declaring it as an argument to each method?
I once used ObjectProvider to do a similar thing, like:
#RequestScope
#Component
public class MyObj // ...
Usage:
#Component
public class OtherObj {
#Autowired
private ObjectProvider<MyObj> provider;
// ...
#Override
public boolean meth() throws Exception {
MyObj o = provider.getIfAvailable();
// ...
But there I found that if no instance exists, it is created instead of being returned null or an exception being thrown.
You can create one utility class, which provides you the principal.
public static Principal getPrincipal() {
SecurityContext securityContext = SecurityContextHolder.getContext();
return securityContext.getAuthentication().getPrincipal();
}
Ofcourse, here you would need to put the null checks in case the context or authentication is null.

Throw exception if bean is defined twice?

In my project I have different services. Each service can define its own Permissions. For each permission, a bean will created. This way, the Authorization service can inject all available permission, without actually knowing them.
The Permission definition of ServiceA will look like this:
#Configuration()
public class ServiceAPermissions extends Permissions {
private static final String BASE = "servicea";
public static final String SERVICEA_READ = join(BASE, READ);
public static final String SERVICEA_WRITE = join(BASE, WRITE);
#Bean()
Permission getReadPermission() {
return new Permission(SERVICEA_READ);
}
#Bean()
Permission getWritePermission() {
return new Permission(SERVICEA_WRITE);
}
}
ServiceB will define the following Permissions:
#Configuration()
public class ServiceBPermissions extends Permissions {
private static final String BASE = "serviceb";
public static final String SERVICEB_READ = join(BASE, READ);
#Bean()
Permission getReadPermission() {
return new Permission(SERVICEB_READ);
}
}
Obviously, this will end in a name clash of the defined beans as I have defined a bean with the name getReadPermission twice. If course I can name the methods like getServiceAReadPermission so they will be distinguished, but this only a convention, which might be ignored.
In this situation, Spring doesn't notify me about the duplicate definition, it simply will just instantiate one and ignore the other definition. Is there a way to tell Spring to throw an Exception, if a bean is defined twice? This way one would be always aware of a duplicate definition.
Alternatively, is there a way to tell spring, that it should use a random bean name instead of the method signature? I know that I can give each bean a name manually #Bean(name = "A name"), but I like to avoid that, as a dev will not be forced to do so and still might forget it.
That design does not seem very logical. A bean is supposed to be available only once, you're using it differently.
I'd suggest to provide a PermissionFactory-Bean which does what you need, along the line of
#Component
public class PermissionFactory {
public Permission createFactory() {
// create A or B permission randomly, as you wanted
}
}

Spring: How to autowire or (use new) a bean with constructor parameter and which is not a managed bean

There are many similar questions here but none showing how to do it. Here, how can I autowire CreateDatabaseAction bean and use it? It expects a Shoppingcart object, and it is NOT a spring managed bean. Or do I have to create it with new keyword?
public abstract class AbstractServiceActions {
#Autowired
protected DatabaseModel dbModel;
protected User user;
public AbstractServiceActions(ShopingCart cart) {
this.user = user;
}
And implement it:
#Component
public class CreateDatabaseAction extends AbstractServiceActions {
public CreateDatabaseAction(ShoppingCArt cart){
super(cart);
}
}
There's no way for Spring to know what ShoppingCart instance to use when instantiating CreateDatabaseAction if there is no managed bean of that type. I think that you should reconsider the design. For example send it as method parameter where it's actually used and remove it from the constructor.
Considering only the names, I would say that ShoppingCart would be a good candidate for a session scoped bean.

Java How to make object use it's implemented static interface method

I have an class with a static interface within it.
public class UserInfo {
private Store userInfoStore;
public static interface Store {
UserInfo save(UserInfo userInfo);
}
public UserInfo save() {
if (userInfoStore == null) return null;
return userInfoStore.save(this);
}
}
I then have an object which implements the above object's interface
public class UserAuditService implements UserInfo.Store {
#Override
public UserInfo save(UserInfo userInfo) {
// code that persists object to disk
}
}
Now say I'm creating an instance of the UserInfo object somewhere else in my application. How do I reference the save method implemented in the UserAuditService class?
UserInfo userInfo = new UserInfo();
??? - Not sure what to do here.
If save method is what you want to call then do the following:
UserInfo userInfo = new UserInfo();
UserInfo.Store userStore = new UserAuditService();
userStore.save(userInfo);
This is one way of using the implemented method.
You mean you don't want to hardcode the UserAuditService class, because there may be many implementations in the future?
There are many solutions, it's what the dependency injection is all about.
You may use Spring or other dependency injection framework, and configure the class to use in xml (or by annotations).
You may do it by hand, for example using constructor dependency injection (you add field of type UserInfo.Store to the UserInfo class, and assign to it a class passed as parameterin a constructor of UserInfo).
Another option is setter dependency injection - you have the same field in UserInfo, but you set it in a setter called from some place after the UserInfo was created.
This makes it clear what happens, but requires to pass the dependencies all the way from the place you configured it to the place they are used, that's why people use dependency injection frameworks to cut the boilerplate.

Categories

Resources