Can I have public static fields in service bean? - java

I'm a bit sceptic of this code, since it kind of violates YAGNI. I need some public static fields for my service class, but usually it's a bad design when you have those in your service bean, so I created an interface for that service, but I'm not sure it's the right choice. Should I have those fields in service class?
public interface IYouTubeServiceBuild {
/**
* Define a global instance of the HTTP transport.
*/
public static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
/**
* Define a global instance of the JSON factory.
*/
public static final JsonFactory JSON_FACTORY = new JacksonFactory();
/**
* Define a global variable that identifies the name of a file that
* contains the developer's API key.
*/
public static final String PROPERTIES_FILENAME = "youtube.properties";
}
#Service
#Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
public class YouTubeServiceBuild implements IYouTubeServiceBuild {
#Getter
private Properties properties;
/**
* Define a global instance of a Youtube object, which will be used
* to make YouTube Data API requests.
*/
#Getter
private YouTube youtube;
#PostConstruct
public void init() {
properties = new Properties();
youtube = new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, request -> {
}).setApplicationName("youtube-search-demo").build();
//etc...
}
}
}
Above service class is then used in other service as follows:
#Service
public class YouTubeApiService {
#Autowired
private YouTubeServiceBuild serviceBuild;
public List<SearchResult> searchYouTube(String searchQuery) {
List<SearchResult> searchResults =
executeSearch(searchQuery, serviceBuild.getProperties(), serviceBuild.getYoutube());
//etc...
}

If the question is whether its possible to set public static fields in Spring managed bean - then yes, its possible, although I completely agree with you that its a bad design.
Leaving alone spring, putting constants in the interface so that the implementations of the interface will be able to access them is considered a code smell because all the implementations (assuming there are many) now can behave differently because some constant changes, or even worse - won't compile anymore if the constant is removed (what if not all the implementations are in the project).
Much better approach is creating a class of constants:
public class YouTubeConstants {
public static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
public static final JsonFactory JSON_FACTORY = new JacksonFactory();
...
}
In the class that needs an access to these constants you can use YouTubeConstants.HTTP_TRANSPORT (or even shorted with static imports).
Now as for the presented design, let me propose an alternative:
The class YouTubeApiService basically needs an access to YouTube object only, it needs it to perform queries. No need for YouTubeServiceBuild intermediate object, no need for connection properties), IMHO it only complicates the code.
You can do something like this:
#Service
public class YouTubeApiService {
#Autowired
private YouTube youtube;
public List<SearchResult> searchYouTube(String searchQuery) {
List<SearchResult> searchResults =
executeSearch(searchQuery,youtube);
//etc...
}
}
Looks much better, doesn't it?
Now in order to create a youtube object, you need some code that goes a little bit beyond the regular "new". You can use a Configuration for this:
import static YoutubeConstants.*;
#Configuration
public class YouTubeConfig {
#Bean
public YouTube youtube() {
return new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, request -> {
}).setApplicationName("youtube-search-demo").build();
}
}
In this implementation there is no need in a YouTubeBuilder at all
One more things to consider:
It seems that you're trying to load some properties by yourself, notice, spring can to it alone.
I haven't seen any real usage of these properties in the code presented in the question, so I can't provide the working example, but please make sure you understand how to load properties in spring, you might inject the already-loaded properties into the youtube method in the configuration.

Related

How to stub private method without powermock

I have a class with a private method that calls some external class and executes it, how can I prevent this without using powermock? (the project uses Junit5 which at this point does not not support powermock yet).
I considered moving these functions outside, but I feel that sometimes methods really belong in a particular class because they are part of it, and it makes no sense to me to move them out, below is just an example to illustrate.
I already know most people will say not to test private methods, but a. I don't completely agree, and b. I'm not trying to test the method here, just to prevent it executing an external call, even to a fake api url.
public class GenericOauth2Client implements Oauth2Client {
private NetHttpTransport HTTP_TRANSPORT;
private JsonFactory JSON_FACTORY;
public GenericOauth2Client(<some_args>) {
...
HTTP_TRANSPORT = new NetHttpTransport();
JSON_FACTORY = new JacksonFactory();
}
public foo(<some_args>) {
...
fetchRefreshTokenResponse( < some_args >);
...
}
private TokenResponse fetchRefreshTokenResponse(<some_args>)
throws IOException {
return new RefreshTokenRequest(HTTP_TRANSPORT, JSON_FACTORY, new GenericUrl(tokenServerUrl),
refreshToken.tokenValue)
.setClientAuthentication(new BasicAuthentication(clientId, clientSecret))
.execute();
}
}
How can this be handled / tested properly?
My approach is usually to make the method protected and create a little helper class for the test which derives from the class under test and override the protected method with a stub implementation.
Make another constructor for it that's not public. Also "program to the interface" so that you can inject behavior more easily
public class GenericOauth2Client implements Oauth2Client {
private HttpTransport transport;
private JsonFactory jsonFactory;
public GenericOauth2Client(<some_args>) {
...
transport = new NetHttpTransport();
jsonFactory = new JacksonFactory();
}
GenericOauth2Client(<some_args>, HttpTransport t) {
this(args);
transport = t;
}
Alternatively, if you have no control over the http client, but can change the url, then WireMock would be the other option to mock the server responses

How does Spring-Boot handle requests that are put through a singleton class?

I'm currently developing a class structure that uses singleton classes for each RequestMapping. I understand that Spring (by default) handles requests in a multi-threading capacity, but I just want to make sure what I'm laying-out now will eventually work in the way I'm intending.
In addition, if, for instance, I make a request and the singleton class creates an in-memory database. On a successive request from the same user/client, will the next request be able to use any of the information previously stored, or is the Spring container for requests destroyed (of sorts) when the response is send back, and re-created on a new request?
Finally, if this is bad practice in any way to create a singleton class for this purpose, I'm open to any suggestions. The original intent of creating the singleton class, was to simply make the ScheduleManager class responsible for creating the object in its entirety, that way if later, if I need to have certain steps taken beforehand to create a full ScheduleManager object (say for instance, establishing a connection to a database), then I can do that without having to create an extra parameter to the constructor and making the implementing class (RequestController) responsible for creating such a database connection.
// Partial of RequestController.java
#RestController
public class RequestController {
private static final String DATA_DIR = System.getProperty("user.dir") + "/data/";
private static final Logger LOGGER = Logger.getLogger(RequestController.class);
#PostMapping(value = "/generateSchedules")
public JsonObject scheduleRequest(#RequestBody JsonObject requestedClasses) {
JSONObject request = gsonToJson(requestedClasses);
JSONObject response = ScheduleManager.getInstance().generateSchedules(request);
return jsonToGson(response);
}
}
// Partial of singleton class ScheduleManager
public class ScheduleManager implements RequestManager {
private static ScheduleHandler handler;
private ScheduleManager() {}
private static class ScheduleManagerHolder {
private static final ScheduleManager INSTANCE = new ScheduleManager();
}
public static ScheduleManager getInstance() {
handler = ScheduleHandler.getInstance();
return ScheduleManagerHolder.INSTANCE;
}
public JSONObject generateSchedules(JSONObject request) {
handler.handlePost(request);
List<Schedule> schedules = GoldPan.getInstance().generate();
JSONArray schedulesAsJson = listToJsonArray(schedules);
JSONObject output = new JSONObject();
output.put("schedules", schedulesAsJson);
return output;
}
}
So, what I'm expecting, is that each unique client sending a request to the RequestController will have their own separate entity/container of sorts of the ScheduleManager singleton class, rather than sharing a single ScheduleManager amongst all requests (kinda like the label "singleton" implies in my mind).

Spring Service instance variable in a multi-threaded environment

I recently ran into a race condition issue because of declaring an instance variable inside a default scoped (Singleton scope) Service class. The purpose of the instance variable was to make my code more readable and avoid the constant passing of the same variable to different private methods within the Service class. The example goes:
#Service
public class SomeServiceImpl implements SomeService {
private final StatusRepository statusRepository;
private Predicate<Status> statusPredicate;
#Autowired
public SomeServiceImpl(StatusRepository statusRepository) {
this.statusRepository = statusRepository;
}
#Override
public List<Status> getAllowedStatuses(String userId) {
statuses = statusRepository.getAll();
initPredicate();
appendPredicateA();
appendPredicateB();
List<Status> results = statuses.stream()
.filter(statusPredicate)
.collect(Collectors.toList());
return results;
}
private void initPredicate() {
statusPredicate = p -> p.getDefault().equals("default");
}
private void appendPredicateA() {
statusPredicate.and(p -> p.getA().equals("A"));
}
private void appendPredicateB() {
statusPredicate.and(p -> p.getB().equals("B"));
}
}
This is a very simple example of the kind of things I want to achieve. This is clearly not thread-safe because now the service class is stateful. I could simply resolve this by turning the statusPredicate variable into a local variable and have the void methods return the predicate after it has been appended new conditions, but that would become cluttered like this:
#Override
public List<Status> getAllowedStatuses(String userId) {
statuses = statusRepository.getAll();
Predicate<Status> statusPredicate = p -> p.getDefault().equals("default");
statusPredicate = appendPredicateA(statusPredicate);
statusPredicate = appendPredicateB(statusPredicate);
List<Status> results = statuses.stream()
.filter(statusPredicate)
.collect(Collectors.toList());
return results;
}
It'd be constantly calling to modify the variable and return the variable.
I know a few solutions that can resolve this such as adding #RequestScope on the Service class to ensure each request from the HTTP will get a new instance of the
Service object, or use ThreadLocal on the Predicate variable. However, I'm not quite certain what is the best approach and whether declaring an instance variable in a Service class is even okay to begin with. If it is bad to make Service class stateful to begin with, how should I structure my code to make it cleaner and still keeping it stateless?
Please advise! Thanks in advance :D
Spring Service can be stateful and this is why scopes for.
Default scope of Spring Service is Singleton because this is the widest use case. But you shouldn't use mutable local variables.
Simply, try for a stateless design and use scopes to solve the issue only if the class instantiation is fast otherwise TreadLocal will perform better.

How to mock unreachable third party class properties via Mockito

I have this beautiful scenery in front of me including JSF, jUnit(4.11) and Mockito(1.10.19):
#ManagedBean
#ViewScoped
public class UserAuth implements Serializable {
private List<UserRole> roleList;
private LocalChangeBean localChangeBean;
public UserAuth() {
roleList = new ArrayList<UserRole>();
localChangeBean = (LocalChangeBean) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("localChangeBean");
setLocalChangeBean(localChangeBean);
setRoleList(getLocalChangeBean().getRoleList());
//many other property setting and some JSF stuff
}
public boolean checkAuth() {
for (UserRole role : getRoleList()) {
if(role.getName().equals("SUPER_USER"))
return true;
}
return false;
}
}
//A hell of a lot more code, proper getters/setters etc.
Here is the test class:
public class UserAuthTest {
#Test
public void testCheckAuth() {
UserAuth bean = mock(UserAuth.class);
List<UserRole> mockRoleList = new ArrayList<UserRole>();
UserRole ur = mock(UserRole.class);
when(ur.getName()).thenReturn("SUPER_USER");
mockRoleList.add(ur);
when(bean.getRoleList()).thenReturn(mockRoleList);
assertEquals(true, bean.checkAuth());
}
The thing is; UserRole class is not reachable by me, it's another part of the project. It doesn't have a no-argument constructor and the existing constructor requires other unreachable classes etc. Thus I can't instantiate it. In these circumstances, all I want to do is to make that mock UserRole object behave such as returning the needed String when it's getName() method gets called.
But obviously; when I try to add that UserRole mock object into the List of UserRoles, the behavior that I tried to define is not stored with the object. And yes, the code looks pretty funny in its current stance. Though I left it there to learn what should I do to achieve this simple, little goal of mine.
Post-Edit:
I couldn't manage the problem without changing the original bean, though I followed Jeff's suggestion below and it worked well as a strategy of isolation. I did not mark it as the best answer since the question was "How to mock an unreachable third party class?" (in the current example its the UserRole class) Eventually the noob me understood that "Mocking an unreachable third party class is no different than mocking any other class".
Here is how I managed it:
#ManagedBean
#ViewScoped
public class UserAuth implements Serializable {
private List<UserRole> roleList;
private LocalChangeBean localChangeBean;
public UserAuth() {
//the actual constructor including all JSF logic, highly dependent
}
UserAuth(List<UserRole> roleList) {
setRoleList(roleList);
//package private test-helper constructor which has no dependency on FacesContext etc.
}
public boolean checkAuth() {
for (UserRole role : getRoleList()) {
if(role.getName().equals("SUPER_USER"))
return true;
}
return false;
}
}
And here is the test class (attention to the iterator mock, it has the whole trick):
public class UserAuthTest {
private UserRole mockRole;
private Iterator<UserRole> roleIterator;
private List<UserRole> mockRoleList;
private UserAuth tester;
#SuppressWarnings("unchecked")
#Before
public void setup() {
mockRoleList = mock(List.class);
mockRole = mock(UserRole.class);
roleIterator = mock(Iterator.class);
when(mockRoleList.iterator()).thenReturn(roleIterator);
when(roleIterator.hasNext()).thenReturn(true, false);
when(roleIterator.next()).thenReturn(mockRole);
tester = new UserAuth(mockRoleList);
}
#Test
public void testCheckAuth(){
when(mockRole.getName()).thenReturn("SUPER_USER");
assertEquals("SUPER_USER expected: ", true, tester.checkAuth());
}
You don't need Mockito. A quick refactor will do this for you.
Your problem: Your code relies on a static call to FacesContext.getCurrentInstance() in your constructor, that is difficult to prepare or substitute out in tests.
Your proposed solution: Use Mockito to substitute out the FacesContext instance, the external context, or the session map. This is partly tricky because Mockito works by proxying out the instances, so without PowerMock you won't be able to replace the static call, and without a way to insert the mock into FacesContext or its tree, you have no alternative.
My proposed solution: Break out the bad call FacesContext.getCurrentInstance().getExternalContext.getSessionMap() into the default constructor. Don't call that constructor from tests; assume it works in the unit testing case. Instead, write a constructor that takes in the session map as a Map<String, Object>, and call that constructor from your tests. That gives you the best ability to test your own logic.
#ManagedBean
#ViewScoped
public class UserAuth implements Serializable {
// [snip]
public UserAuth() {
// For the public default constructor, use Faces and delegate to the
// package-private constructor.
this(FacesContext.getCurrentInstance().getExternalContext().getSessionMap());
}
/** Visible for testing. Allows passing in an arbitrary map. */
UserAuth(Map<String, Object> sessionMap) {
roleList = new ArrayList<UserRole>();
localChangeBean = (LocalChangeBean) sessionMap.get("localChangeBean");
setLocalChangeBean(localChangeBean);
setRoleList(getLocalChangeBean().getRoleList());
// [snip]
}
}
p.s. Another solution is to actually get the session map within the test and insert the value you need, but you have to be careful there not to pollute your other tests by installing something into a static instance that may persist between tests.

Managing configurations in java (initial config / save/load config)

I got a class Config wich looks like that:
public Class Config {
public static int someIntValue = 0;
public static String someText = "some text";
}
What i want to do now is saving and loading that config and there is also that inital config if there is no need to load another. So the config can change at any point in the programm.
What i came up with was a Singelton like pattern
public Class Config {
public static Config instance;
private int someIntValue = 0;
private int String someText = "some text";
public static Config getInstance(){
if(instance == null)
instance = new Config();
return instance;
}
public void setInstance(Config config){
this.instance = config;
}
//getter/setter
...
}
But in the end it doesnt look like the best approach and im not quite happy with it :/
Maybe you guys can help me out with a usual / "best practice" way to do that.
Best Regards
Made
I would just use java.util.Properties, or some wrapper around it. Another good approach is java bean and something like xstream to save/load stuff.
Usually in Java for configuration use properties files. And then use ResuorseBundle for reading properties.
Your "singleton" is not a Singleton in the conventional sense.
1) Field instance must be private
2) Remove SetInstance method
3) And you should make your singleton thread safe.
If you'd consider avoiding writing the boilerplate code around java.util.Properties, you can have a look at something that does it for you: OWNER API.
It's configurable to tailor your needs and it offers some additional neat features if compared to java.util.Properties (read the docs).
Example. You define an interface with your configuration parameters:
public interface ServerConfig extends Config {
int port();
String hostname();
#DefaultValue("42")
int maxThreads();
#DefaultValue("1.0")
String version();
}
Then you use it like this:
public class MyApp {
private static ServerConfig cfg = ConfigFactory.create(ServerConfig.class);
private MainWindow window;
public MyApp() {
// you can pass the cfg object as dependency, example:
window = new MainWindow(cfg);
}
public void start() {
window.show();
}
public static void main(String[] args) {
// you can use it directly, example:
System.out.println("MyApp version " + cfg.version() + " copyright (c) ACME corp.");
MyApp app = new MyApp();
app.start();
}
}
You can define the cfg object as member instance on the classes where you need, or you can pass the instance to constructors and methods where you need it.
Version 1.0.4 will be released soon and it will include also "hot reload" and many improvements.

Categories

Resources