Architecture of a class, and best practice? [closed] - java

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
So I am in charge of creating a project that has to do with calculations of pay. One aspect of the project is to analyze a proper input such as 4:00 PM, and other aspects including calculating the pay for the hours put in, and the type of job etc.
my question more so has to do with the best practices for designing the classes around this.
Should I have one class that analyzes the input string, and only does that? and one class for the calculator to display the proper output or should it all be in one class?
both ways are fine for me to do, but what is considered professional?
is it best practice to split classes based on their unique functionality even if you dedicate a class to simply one method?

At the boundary of your application you'll be accepting requests through a user interface or a system interface. You should treat anything originating from outside your application as untrusted and potentially wrong. For example, if you receive a HTTP request there is no guarantee that it is valid and contains the fields you expect. If you read form a file, it might be incorrectly formatted.
There should be a layer at the boundary of your application which takes input (which is just a bunch of bytes in the end) and turns it into a representation as Java objects of the suitable type (e.g. Boolean, LocalDate). If everything is a String, you are probably doing it wrong.. If this layer is unable to do this, it should send back an error.
Once you have expressed the request as a correctly typed Java objects, your business logic should process the request. This makes it possible to use the same logic when data is provided through a different interface, separates plumbing (parsing) from business logic (calculations). It allows the business logic to be more easily unit tested.
When you output a response back to the user (or system), you should convert from your nicely structured Java objects back to the output representation at the last moment.

I suggest you take a look at the javax.validation package and the Bean Validation JSR's 1.0 and 2.0
Using this approach you can create Java classes to represent your data and annotate them with the required validations. Triggering the validation to happen depends a little bit on the context.
In a Spring Boot application putting #Valid on the received controller parameter does the trick. See also this cheat sheet:
import javax.validation.Valid;
import com.company.app.model.Article;
#Controller
public class ArticleController {
...
#RequestMapping(value="/postArticle", method=RequestMethod.POST)
public #ResponseBody String postArticle(#Valid Article article, BindingResult result, HttpServletResponse response){
if(result.hasErrors()){
String errorMessage = "";
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
List<ObjectError> errors = result.getAllErrors();
for( ObjectError e : errors){
errorMessage+= "ERROR: " + e.getDefaultMessage();
}
return errorMessage;
}
else{
return "Validation Successful";
}
}
}
In a standalone application it could be done like this:
public class BeanValidationExample {
public static void main (String[] args) {
Configuration<?> config = Validation.byDefaultProvider()
.configure();
ValidatorFactory factory = config.buildValidatorFactory();
Validator validator = factory.getValidator();
factory.close();
Person person = new Person();
person.setDateOfBirth(new Date(System.currentTimeMillis() + 10000));
Set<ConstraintViolation<Person>> violations = validator.validate(person);
violations.forEach(v -> System.out.println(v.getPropertyPath() +
"- " + v.getMessage()));
}
}

Related

Intercept outgoing HTTP requests [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 4 years ago.
Improve this question
so I'm looking for a library or some way of intercepting any outgoing HTTP requests from my Java application? Why? Because I want to unit test an API integration and since I'm using a library (wrapper) for that API, I can't modify any of it's code. It's not my code that's actually making the HTTP requests.
So, I need to intercept them, view them and assert they are correct according to the API's documentation.
I've tried looking online, but I couldn't find the exact thing I'm looking for. Most libraries out there will let me do it, only if I configure the requests themselves properly, but I can't do that, since they're made by an API wrapper, not my code.
Cheers
P.S Some example code
String path = "/some/path";
String repoOwner = "John Doe";
String repoName = "John repo"
GitHubClient client = new GitHubClient();
client.setCredentials(this.username, this.password);
RepositoryService repositoryService = new RepositoryService(client);
CommitService commitService = new CommitService(client);
Repository repo = repositoryService.getRepository(repoOwner, repoName);
List<RepositoryCommit> commits = commitService.getCommits(repo, null, path);
This will use the API wrapper to get all the commits in a given repository. Suppose I wanted to see the HTTP requests this code is making and then I wanted to Unit Test them and assert they are correct. How would I do that? Is there any way to intercept them, catch them kind of like an exception, and do stuff with them, such as assertions?
What you're trying to do is not easy and from my point of view it doesn't make much sense.
You're trying to test your application but mostly you're trying to test the GitHubClient library.
If I were you I would use only mocks in your tests and verify the input arguments. So the test would like like this (using mockito):
List<RepositoryCommit> commits = new ArrayList<>();
commits.add(new RepositoryCommit(....));
commits.add(new RepositoryCommit(....));
when(commitService.getCommits(repo, null, path)).thenReturn(commits);
That way you avoid of the library testing.
If you want to actually investigate what the library does - what requests it sends and what is going on - I would recommend you to go through the library code, find the place where the request is actually set up and just run your app in debug mode and add a breakpoint there.
If you really want to handle (e.g. log, replicate...) the real requests to GitHub even in production you could use AspectJ for that. That would change the byte code so that you could wrap particular method calls. Again you would have to find the place in the GitHub library where the real GitHub (I suppose HTTP) call is performed and attach aspect to that call. In aspect you basically declare which method you want to intercept and what you want to do before its call or after. I'm not really expert in this area so I can't provide you more info - there is a tutorial about Aspects - https://eclipse.org/aspectj/doc/next/progguide/starting.html
Other option is also install some network watch tool like wireshark
EDIT
Other option how to avoid costly calls to GitHub is to create a simple wrapper like this:
public class GitHubServiceImpl implements GitHubService {
private Rpository repo;
/** other methods **/
#Override
public List<RepositoryCommit> getAllCommits(String path) {
return commitService.getCommits(repo, null, path));
}
}
And here is the actual service you want to test.
public class CommitService {
private GitHubService gitHubService;
private String path;
public List<RepositoryCommit> getAll() {
return gitHubService.getAllCommits(path);
}
}
and for integration tests create special implementation of the GitHubService interface:
public class TestGitHubService implements GitHubService {
private Map<String, RepositoryCommit> preArrangedCommits;
/** other methods **/
public void setPreArrangedCommits(Map<String, RepositoryCommit> preArrangedCommits) {
this.preArrangedCommits = preArrangedCommits;
}
#Override
public List<RepositoryCommit> getAllCommits(String path) {
return preArrangedCommits;
}
}
and in the test call:
public class CommitServiceIntegrationTest {
// #Autowired, #Bean maybe?
private CommitService commitService;
// #Autowired, #Bean maybe?
private GitHubService gitHubService;
public void testGetAll() {
Map<String, RepositoryCommit> preArrangedCommits = new HashMap<>();
preArrangedCommits.put("path/", new RepositoryCommit(...));
gitHubService.setPreArrangedCommits(preArrangedCommits);
List<RepositoryCommit> commits = commitService.getAll();
assertEquals(commits, preArrangedCommits);
}
}
I would go this way.
Frank

How to send request parameters to business logic [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
I know that it's bad idea to embed business logic in your servlets, it's accepted to do on application server's side. Sometimes you have a lot of parameters in your request, and all of them you need to send to classes that represents your business logic. How would be better to do it? (I thought about JavaBeans but they were designed for another purpouse.)
Thanks.
You should separate your business logic into a separate class, which implements an interface, and the servlet class should simply be responsible for deserialising the input stream into some kind of request object, passing it to the business logic object, and then serialising the response. If you add a little bit of DI magic then it can become fairly simple to locate and construct the correct implementation of the business logic class to use.
Example
public interface TheBusiness {
MyBusinessResponse doProcess(MyBusinessRequest request);
}
public final class MyBusinessClass implements TheBusiness {
#Override
public MyBusinessResponse doProcess(MyBusinessRequest request) {
// all the complex logic goes here.
return response;
}
}
public class MyBusinessServlet extends HttpServlet {
private final TheBusiness theBusiness;
private final ObjectMapper objectMapper;
public MyBusinessServlet() {
theBusiness = // locate and construct implementation.
objectMapper = // Initialise Jackson deserialisation.
}
public void doGet(HttpServletRequest request, HttpServletResponse response) {
final MyBusinessRequest requestBody = objectMapper.readValue(
request.getInputStream(), MyBusinessRequest.class);
final MyBusinessResponse responseBody = theBusiness.doProcess(requestBody);
objectMapper.writeValue(response.getOutputStream(), responseBody));
}
}
The only tricky thing here is instantiating your MyBusinessClass. There are patterns for different DI frameworks which can help there. Mostly they involve using a framework-provided servlet to do all that marshalling and unmarshalling for you and you just need to code up the business logic and annotate a class appropriately. Both Spring-MVC and Jersey do that. The important thing is that the servlet class deals with all the HTTP-type interaction and with serialisation, while the logic is encapsulated elsewhere behind an interface - so each class can be well tested in isolation.

A good practice to present service level validation errors to the user using Spring MVC

Are there some good practices to present service layer validation errors using Spring MVC after "shallow" user input validation has been performed using Spring MVC Validators? For example, having this code:
#Autowired
private UserService userService;
#RequestMapping(value = "user/new", method = RequestMethod.POST)
public String createNewUser(#ModelAttribute("userForm") UserForm userForm, BindingResult result, Model model){
UserFormValidator validator = new UserFormValidator(); //extending org.springframework.validation.Validator
validator.validate(userForm, result);
if(result.hasErrors()){
model.addAttribute("userForm", userForm);
return "user/new";
}
// here, for example, the user already might exist
userService.createUser(userForm.getName(), userForm.getPassword());
return "redirect:user/home";
}
While it may seem trivial having this code as an example, it seems to be a delicate story to me when validation at service layer is a complex task. Despite being an absurd scenario, the UserService might take a list of users to create, and if one of them already exists, then the view tier must somehow be notified about which of them is not valid (e.g. does already exist).
I am looking for a good practice how to design a piece of code, which makes it possible to
1) handle validation errors at the service layer having complex data as input, and
2) to present these validation errors to the user
as easy as possible. Any suggestions?
The choice is typically exceptions vs. error codes (or response codes), but the best practice, at least Bloch's, is to only use exceptions in exceptional circumstances, which disqualifies them in this situation, since a user picking an existing username isn't unheard of.
The issue in your service call is that you assume createUser is an imperative command with no return value. You should think of it as "try to create a user, and give me a result" instead. That result could then be
an integer code (horrible idea)
a constant from a shared Result enum (still a bad idea due to maintainability)
a constant from something more specific like a UserOperationResult enum (better idea since you might want to return USER_ALREADY_EXISTS both when you create a new user and when you try to modify a user)
a UserCreationResult object that's completely custom to this call (not a good idea because you'll get an explosion of these)
a Result<T> or UserOperationResult<T> wrapper object that combines a response code constant (ResultCode or UserOperationResultCode respectively) and a return value T, or a wildcard ? when there is no return value ... just watch out for pointcuts and the like that don't expect the wrapper)
The beauty of unchecked exceptions is that they avoid all this crap, but they come with their own set of issues. I'd personally stick to the last option, and have had decent luck with it in the past.
An alternative to throwing an exception/returning an error code would be to pass the Errors to userService.createUser(). The duplicate username check could then be performed at the service level - and any error appended to the Errors. This would ensure that all errors (shallow and more complex) could all be collected up and presented to the view at the same time.
So you could rework your controller method slightly:
#RequestMapping(value = "user/new", method = RequestMethod.POST)
public String createNewUser(#ModelAttribute("userForm") UserForm userForm, BindingResult result, Model model){
UserFormValidator validator = new UserFormValidator();
validator.validate(userForm, result);
// Pass the BindingResult (which extends Errors) to the service layer call
userService.createUser(userForm.getName(), userForm.getPassword(), result);
if(result.hasErrors()){
model.addAttribute("userForm", userForm);
return "user/new";
}
return "redirect:user/home";
}
And your UserServiceImpl would then check for duplicate users itself - for example:
public void createUser(String name, String password, Errors errors) {
// Check for a duplicate user
if (userDao.findByName(name) != null) {
errors.rejectValue("name", "error.duplicate", new String[] {name}, null);
}
// Create the user if no duplicate found
if (!errors.hasErrors()) {
userDao.createUser(name, password);
}
}
The Errors class is part of Spring's validation framework - so although there would be a dependency on Spring, the service layer wouldn't have any dependency on any web related code.

When is actually a custom validator needed in Struts2?

We have the validate() method directly available in our action classes in which we can put our own logic to perform some kind of validations we need.
For example, if I need to validate two fields regarding date-time, I can put my own logic in the validate() method something like the following.
public final class DiscountAction extends ActionSupport implements ValidationAware, ModelDriven<Discount>
{
private Discount entity=new Discount();
#Override
public Discount getModel() {
return entity;
}
#Override
public void validate()
{
if(entity.getDiscountStartDate()!=null&&entity.getDiscountEndDate()!=null)
{
final int period=30;
final DateTime startDate=entity.getDiscountStartDate().withZone(DateTimeZone.forID("Asia/Kolkata")).withMillisOfSecond(0);
final DateTime endDate=entity.getDiscountEndDate().withZone(DateTimeZone.forID("Asia/Kolkata")).withMillisOfSecond(0);
final DateTime currentDate=new DateTime(DateTimeZone.forID("Asia/Kolkata"));
final int daysBetween = Days.daysBetween(startDate, endDate).getDays();
if(startDate.isAfter(endDate))
{
addFieldError("discountStartDate", "The start date must be earlier than the end date.");
}
else if(startDate.equals(endDate))
{
addFieldError("discountEndDate", "Both the dates can not be same.");
}
else if(DateTimeComparator.getDateOnlyInstance().compare(currentDate, endDate)==0 || endDate.isBefore(currentDate))
{
addFieldError("discountEndDate", "Can not be today's date or any day before today.");
}
else if(Days.daysBetween(startDate, endDate).getDays()<1)
{
addFieldError("discountEndDate", "There must be an interval of at least one day.");
}
else if(daysBetween>period)
{
addFieldError("discountEndDate", "The discount period is valid only upto "+period+(period==1?" day":" days")+" period which it excceds. The actual difference is "+daysBetween);
}
}
}
}
Assuming entity is an instance of the model class.
Why do we need a custom validator here? I have not yet tried a custom validator, since it is not needed yet.
Could you please show me a real situation/example where a custom validator is precisely need?
Custom validators are used when:
You want to use annotation- or XML-based validation
You want to re-use the same validation across many actions, with the caveat that...
...if the validation already exists in external logic, which it should anyway, you can re-use it in validate methods as well
The business logic for custom validators should already exist as a separate entity. It should not exist as code embedded in an action; it makes both the action, and the validation, much harder to test.
When the logic is located in its appropriate place, it's easy to use in either a validator or a validate method. The advantage is easy re-use in XML and/or annotations.
In such point-of-view, I can also claim that Struts2 is not needed too because I can implement my web application using C++. Could you accept? I think no, because using an MVC pattern such Struts2 makes your application more clean and maintainable. Also, you do not have to redo things again yourself when they're implemented already.
In same way, if you want to use already implemented and tested best practices and also if you would like to save time and money by not doing things from scratch, and if you like maintainable codes using separated concerns ... then you need to use Struts2 custom validators instead of that ugly validate method (It's ugly because aspects such validations should not mixed with business logic - see AOP).

How do we actually implement the entity boundary control pattern in java? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I am trying to create a library management system. Now, I know that the boundary cannot interact with the entity directly. The control class acts as a mediator between the boundary and the entity classes. However, when are the objects of these classes created?
First, lets talk about the login. The boundary will be the login form's UI created using Java Swing. The Controller class will be PersonController which contains a function called "validateUser()". The Entity class called User contains the use's information and accesses the database.
Now, I need to create the UI, fetch username & password from the UI using action listeners and then, create a User entity with the username & password, and then, call validateUser() method of the PersonController to check if the login is correct and the user is valid.
How do I do this? Where do I create these objects?
Here's my code till now:
public class MainClass { // main class
public static void main(String[] args) {
PersonController loginSession = new PersonController(); //UNSURE
}
}
public class PersonController {
public PersonController(){
LoginUI loginForm = new LoginUI(); //UNSURE
loginForm.setVisible(true); //UNSURE
}
//implementation of the validateUser() function
}
public class User {
private String username;
private String password;
private String role;
private String name;
private String phone;
private String email;
// get & set methods and accessing the database
}
public class LoginUI{
//entire code for the UI in Java Swing created using Netbeans IDE
}
To my mind the process should work something like this...
You have three elements, the UI, the model and the controller.
The UI presents choices to the user...
The model will be required to create a User object (as your UI should not have the knowledge of how this is actually achieved).
The controller will be responsible for responding to events from the UI and making decisions on what it should do.
When the user types in there values and clicks the "accept" action (what ever it might be), the controller captures that event and requests from the UI a User object. The UI takes the information entered by the user and asks the model to create a User object with these values.
The controller can they validate the User object.
At any point any part of the process may choose to throw an exception. As the UI is the only part of the system that can actually talk back to the user, it's the UI's responsibility to show these errors.
The basic work flow might look something like this...
Create the model, form and controller.
Add the model to the form, add the form to the controller.
The interaction between these distinct elements MUST be done via interfaces where ever possible. No part should know more about the other part then it absolutely needs to - IMHO.
My first step would be - get it clear in your mind what it is you want to achieve. Work out who is responsible for what and design the bridges you need to connect them together

Categories

Resources