select from MyBatis only get one result - spring

I am facing a very weird problem.
I used MyBatis generator automatically generate mappers and xml from my MySQL databases.And used the selectByExample method of the mapper to pass criteria trying to verify the user. Below is the code.
#Service
public class EmployeeServiceImpl implements EmployeeService {
#Autowired
private EmployeeMapper employeeMapper;
#Autowired
private EmployeeExample employeeExample;
#Override
public boolean verify(String username,String password) {
EmployeeExample.Criteria criteria = employeeExample.createCriteria();
criteria.andUsernameEqualTo(username);
criteria.andPasswordEqualTo(password);
List<Employee> list = employeeMapper.selectByExample(employeeExample);
if(list.size()>0) {
return true;
}else {
return false;
}
}
}
When I use SpringMVC controller passing the username and password to the mapper, it just returns only one result. When I pass correct information it will return true, but after that, every incorrect information gets true also.
I'm not sure if is it the MyBatis problem or Spring MVC?
Could anyone help me with that?
Really appreciate!

I just fixed the problem with not injecting the EmployeeExample and "new" one instead. But is it violating the decoupling principle? And how that problem happens? Could anyone explain it a little bit? Appreciate again!

Related

how to write Test case for if else using mockMvc in spring boot

How can i write Mockmvc test case for below code:
My controller class
#RestController
public class CartController {
#Autowired
private CartService cartService;
#GetMapping(path = "/addToCart", produces = MediaType.APPLICATION_JSON_VALUE)
public String cart(#Valid #RequestBody Cart cart) {
return cartService.cart(cart);
}
}
My CartService class:
#Service
public class CartService {
private LoginRepository loginRepository;
#Autowired
private ProductRepository productRepository;
#Autowired
private CartRepository cartRepository;
#Autowired
private EmailService emailService;
public CartService(LoginRepository loginRepository) {
this.loginRepository = loginRepository;
}
public String cart(Cart cart) {
String username = cart.getUserName();
System.out.println(username);
String password = cart.getPassword();
String email = cart.getEmail();
if (loginRepository.existsByUserNameAndPassword(username, password)) {
String productname = cart.getProductName();
System.out.println(productname);
String price = cart.getPrice();
String discription = cart.getDiscription();
if (productname != null) {
if (productRepository.existsByProductNameAndPriceAndDiscription(productname, price, discription)) {
Integer count = cartRepository.countByUserName(username);
System.out.println(count);
cartRepository.save(new Cart(username, password, email, productname, price, discription, count));
return "{\"message\":\"product Successfully added to cart\"}";
} else {
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "entity not found"
);
}
} else {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
}
} else {
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
}
I don't know how to write test case for above code using mockmvc. i don't know how can i write mockmvc test case for if else statement. so please help me how to write mockmvc test case for entire code so that i can do mockmvc test for if else statment also.
I think you have a misunderstanding of what #WebMvcTest is used for.
It is for Integration Testing a single slice of your Application – namely Web MVC.
This means that your #WebMvcTest annotated Test should only use Mocks of your Service because what they should test is all the Web related stuff (proper conversion to JSON, XML; returning correct response codes, etc)
There is a tutorial on spring.io which should answer your questions.
For Testing your Service you can use plain old Unit Test with for example JUnit.
In order for that to work you need to do some rework on your classes. First thing I would suggest is to replace the field injections with constructor injection. This is the recommended way of injection. Read here for more information.
After this change you can mock the dependencies of your Service (for example with Mockito) and pass them via the constructor.
This way you can test the different if/else branches in your code.
And last but not least I would highly recommend to do some other rework on your service. Currently it returns information that are highly coupled to the Web context(the manually crafted JSON, the ResponseStatusException). The handling of those is the responsibility of your controller. Your Service should be independent of the thing (the controller in your case) that uses it. Just imagine your Service will be used by a other Class for a CLI Tool which does know nothing about JSON and response statuses.

Spring 5 Webflux functional endpoints - How to perform input validation?

According to the current doc (5.0.0.RELEASE) Spring Webflux supports validation when working with annotated controllers:
By default if Bean Validation is present on the classpath — e.g.
Hibernate Validator, the LocalValidatorFactoryBean is registered as a
global Validator for use with #Valid and Validated on #Controller
method arguments.
However nothing is said about how to automate it with functional endpoints. In fact, the only example of input processing in the documentation doesn't validate anything:
public Mono<ServerResponse> createPerson(ServerRequest request) {
Mono<Person> person = request.bodyToMono(Person.class);
return ServerResponse.ok().build(repository.savePerson(person));
}
Are we supposed to do this manually or there is some automatic way to do it?
In Spring version 5.0, there is no automatic way to do validation in functional endpoints, and as such validation must be done manually.
Though there are currently no concrete plans to do so, we might add some sort of validation in the future. But even then it will be an explicit method call, and not an automatic mechanism. Overall, the functional endpoint model is designed to be a lot more explicit than the annotation-based model.
As arjen-poutsma said, it seems there is no way of running automated validations on Spring 5 functional endpoints.
Spring documentation is not very clear about this, and it doesn't suggest any approach.
On this Baeldung article, you'll find an idea on how you can run validations using this approach (disclaimer: I'm the writer of the article :) )
In a nutshell, you can follow these steps:
Implement Spring Validators to evaluate your resources
Create an abstract class with the basic procedure that any handler will follow when processing a request, leaving up to the children classes what to do when the data is valid
Make your request handler classes extend this abstract class, implementing this abstract method, stating the body it will be expecting, and what validator needs to be used to validate it
EDIT:
I've been following this related Spring issue, and it seems we now count with official documentation regarding this subject: https://github.com/spring-projects/spring-framework/blob/master/src/docs/asciidoc/web/webflux-functional.adoc#validation
The suggested approach is to use validators as explained in the article.
At the current version(2.0.4.RELEASE) there isn't a way to do automatic validation with handles, however you always could make a manual validation like this:
#Slf4j
#Component
#FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
#RequiredArgsConstructor
public class MyHandlerValidator implements HandlerValidator<MyResource> {
Validator validator;
#Override
public void callValidator(final MyResource fdr) {
final DataBinder binder = new DataBinder(fdr);
binder.setValidator(validator);
binder.validate();
if (binder.getBindingResult().hasErrors()) {
final String reason = binder.getBindingResult().getFieldError().toString();
log.error(reason);
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, reason);
}
}
}
The thing with this, its that the you should throw a WebExchangeBindException like automatic validation does, however i could't create a MethodParameter witch is a dependency to create this exception.
UPDATE:
Spring show us a way to do it, which is similar to my solution, but, not enough in my opinion on documentation
Just to demo some working code. If you need simple validation based on the object annotations like:
#Value
#Builder
#Jacksonized
public class SigninRequest {
#NotBlank(message = "The username is mandatory")
#Email(message = "The username should be valid Email")
String username;
#NotBlank(message = "The password is mandatory")
String password;
}
At the handler you need just one simple additional operator doOnNext:
#Component
#RequiredArgsConstructor
public class AuthHandler {
private final AuthService authService;
private final ObjectValidator validator;
public Mono<ServerResponse> signin(ServerRequest request) {
return ok().body(
request.bodyToMono(SigninRequest.class)
.doOnNext(validator::validate) //<-- just one single line
.flatMap(login -> authService.authenticate(login.getUsername(), login.getPassword())),
AuthResult.class);
}
}
The ObjectValidator is doing actual validation and throws the runtime exception with the 4xx error in case of validation errors:
#Component
#RequiredArgsConstructor
public class ObjectValidator {
private final Validator validator;
public <T> T validate(T object) {
var errors = validator.validate(object);
if (errors.isEmpty()) {
return object;
} else {
String errorDetails = errors.stream().map(er -> er.getMessage()).collect(Collectors.joining(", "));
throw new ObjectValidationException(errorDetails);
}
}
}
And the exception:
#ResponseStatus(code = HttpStatus.UNPROCESSABLE_ENTITY)
public class ObjectValidationException extends RuntimeException {
public ObjectValidationException(String errorDetails) {
super("Please supply the valid data: " + errorDetails);
}
}
If you properly setup global error handling you can keep you handler code clean and reuse the object validator across all your handlers.

spring boot #Cachable returning all fields of superclasses filled with null values

we are facing a strange problem and I dont quit understand whats going on and hope someone else already had the same issue and has a clue what is going on.
We wrote a simple REST service making use of #Cachable:
#GetMapping(value = "/get/{" + PARAM_TENANT + "}/{" + PARAM_UID + "}")
#Cacheable(value = GET_ORDERS_BY_UID )
public GetOrdersResponseDto getOrdersByUid(#PathVariable final String tenant, #PathVariable final String uid) {
....
return new GetOrdersResponseDto(createCacheKey(), orderResponseDtos);
}
GetOrdersResponseDto consists of several fields. Some contain instances of custom classes, some lists of them and other simple primitive values.
When the GetOrdersResponseDto response is served from the cache all fields of objects that are stored inside a list AND are located in the objects superclass are filled with null values.
We are using hazelcast as the cache implementation. And our cache config is very basic:
#Component
public class HazelcastConfig extends Config {
#Autowired
public HazelcastConfig(final ConfigClient configClient) {
super();
final GroupConfig groupConfig = getGroupConfig();
final String name = configClient
.getConfigPropertyValueOrThrow("public", "com.orderservice.hazelcast.group.name");
groupConfig.setName("foogroup");
final String password = configClient
.getConfigPropertyValueOrThrow("public", "com.orderservice.hazelcast.group.password");
groupConfig.setPassword(password);
The response class looks as follows:
public class GetOrdersResponseDto implements Serializable {
private String cacheSerial;
private List<OrderResponseDto> orderResponseDtos;
}
And the problems occur only for fields of OrderResponseDto that are part of the super class of OrderResponseDto.
I hope someone can give us an hint what's the cause for this strange behaviour.
Edit: I found out, that the problem only occurs for objects that are stored inside lists...
This is Java behaviour. See https://docs.oracle.com/javase/8/docs/api/java/io/Serializable.html
If your object is serializable and extends an object that is not serializable, then instead of the NotSerializeException which would be useful, the fields of the parent object are only initialized which is why you have them as nulls.
You can prove this in a unit test.
Here's one to reuse - https://github.com/hazelcast/hazelcast-code-samples/blob/master/serialization/hazelcast-airlines/the-code/src/test/java/com/hazelcast/samples/serialization/hazelcast/airlines/V1FlightTest.java

Spring Ldaptemplate 2 add member to group

what is best way to add member in group using spring LdapTemplate.
I have successfully create user and remove user ex.
But I'm trying to add member then I'm facing issue.
Add Member Code:
public boolean addMemberToGroup(List<String> groupList, User user) {
boolean isAddedSuccessfully=false;
try{
for(int i=0;i<groupList.size();i++){
Name groupDn = buildGroupDn(groupList.get(i));
DirContextOperations ctx = ldapTemplate.lookupContext(groupDn);
ctx.addAttributeValue("member",buildPersonDn(user.getUid()));
ldapTemplate.update(ctx);
}
isAddedSuccessfully=true;
}
catch(Exception e){
isAddedSuccessfully=false;
}
return isAddedSuccessfully;
}
private Name buildGroupDn(String groupName) {
return LdapNameBuilder.newInstance("cn=groups").add("cn", groupName).build();
}
private Name buildPersonDn(String userID) {
return LdapNameBuilder.newInstance()
.add("uid", userID).add("cn", "users")
.build();
}
Exception Of addMemberToGroup: Class class org.springframework.ldap.core.DirContextAdapter must have a class level interface org.springframework.ldap.odm.annotations.Entry annotation.
please let me know what i am missing.
The updatemethod is intended for use with ODM annotated classes. When working with DirContextAdapter you should use the modifyAttributes method.
Though this is an old question, it's one I had too recently. For anyone coming here in the future, this question is similar to the one found at Spring Malformed 'member' attribute value. Putting together info from both questions, I found the solution to my problem, and share here what worked for me.
In addition to using the modifyAttributes method of the LdapTemplate class, it's also important to pass a String object as the second parameter of the addAttributeValue method of the DirContextOperations class when adding a member, rather than passing a Name object. The toString method called on the corresponding Name object does the trick.
Original code:
DirContextOperations ctx = ldapTemplate.lookupContext(groupDn);
ctx.addAttributeValue("member",buildPersonDn(user.getUid()));
ldapTemplate.update(ctx);
Try this instead:
DirContextOperations ctx = ldapTemplate.lookupContext(groupDn);
ctx.addAttributeValue("member",buildPersonDn(user.getUid()).toString());
ldapTemplate.modifyAttributes(ctx);

Spring Boot equivalent to XML multi-database configuration

I would like to port two projects to Spring Boot 1.1.6. The are each part of a larger project. They both need to make SQL connections to 1 of 7 production databases per web request based region. One of them persists configuration setting to a Mongo database. They are both functional at the moment but the SQL configuration is XML based and the Mongo is application.properties based. I'd like to move to either xml or annotation before release to simplify maintenance.
This is my first try at this forum, I may need some guidance in that arena as well. I put the multi-database tag on there. Most of those deal with two connections open at a time. Only one here and only the URL changes. Schema and the rest are the same.
In XML Fashion ...
#Controller
public class CommonController {
private CommonService CommonService_i;
#RequestMapping(value = "/rest/Practice/{enterprise_id}", method = RequestMethod.GET)
public #ResponseBody List<Map<String, Object>> getPracticeList(#PathVariable("enterprise_id") String enterprise_id){
CommonService_i = new CommonService(enterprise_id);
return CommonService_i.getPracticeList();
}
#Service
public class CommonService {
private ApplicationContext ctx = null;
private JdbcTemplate template = null;
private DataSource datasource = null;
private SimpleJdbcCall jdbcCall = null;
public CommonService(String enterprise_id) {
ctx = new ClassPathXmlApplicationContext("database-beans.xml");
datasource = ctx.getBean(enterprise_id, DataSource.class);
template = new JdbcTemplate(datasource);
}
Each time a request is made, a new instance of the required service is created with the appropriate database connection.
In the spring boot world, I've come across one article that extended TomcatDataSourceConfiguration.
http://xantorohara.blogspot.com/2013/11/spring-boot-jdbc-with-multiple.html That at least allowed me to create a java configuration class however, I cannot come up with a way to change the prefix for the ConfigurationProperties per request like I am doing with the XML above. I can set up multiple configuration classes but the #Qualifier("00002") in the DAO has to be a static value. //The value for annotation attribute Qualifier.value must be a constant expression
#Configuration
#ConfigurationProperties(prefix = "Region1")
public class DbConfigR1 extends TomcatDataSourceConfiguration {
#Bean(name = "dsRegion1")
public DataSource dataSource() {
return super.dataSource();
}
#Bean(name = "00001")
public JdbcTemplate jdbcTemplate(DataSource dsRegion1) {
return new JdbcTemplate(dsRegion1);
}
}
On the Mongo side, I am able to define variables in the configurationProperties class and, if there is a matching entry in the appropriate application.properties file, it overwrites it with the value in the file. If not, it uses the value in the code. That does not work for the JDBC side. If you define a variable in your config classes, that value is what is used. (yeah.. I know it says mondoUrl)
#ConfigurationProperties(prefix = "spring.mongo")
public class MongoConnectionProperties {
private String mondoURL = "localhost";
public String getMondoURL() {
return mondoURL;
}
public void setMondoURL(String mondoURL) {
this.mondoURL = mondoURL;
}
There was a question anwsered today that got me a little closer. Spring Boot application.properties value not populating The answer showed me how to at least get #Value to function. With that, I can set up a dbConfigProperties class that grabs the #Value. The only issue is that the value grabbed by #Value is only available in when the program first starts. I'm not certain how to use that other than seeing it in the console log when the program starts. What I do know now is that, at some point, in the #Autowired of the dbConfigProperties class, it does return the appropriate value. By the time I want to use it though, it is returning ${spring.datasource.url} instead of the value.
Ok... someone please tell me that #Value is not my only choice. I put the following code in my controller. I'm able to reliably retrieve one value, Yay. I suppose I could hard code each possible property name from my properties file in an argument for this function and populate a class. I'm clearly doing something wrong.
private String url;
//private String propname = "${spring.datasource.url}"; //can't use this
#Value("${spring.datasource.url}")
public void setUrl( String val) {
this.url = val;
System.out.println("==== value ==== " + url);
}
This was awesome... finally some progress. I believe I am giving up on changing ConfigurationProperties and using #Value for that matter. With this guy's answer, I can access the beans created at startup. Y'all were probably wondering why I didn't in the first place... still learning. I'm bumping him up. That saved my bacon. https://stackoverflow.com/a/24595685/4028704
The plan now is to create a JdbcTemplate producing bean for each of the regions like this:
#Configuration
#ConfigurationProperties(prefix = "Region1")
public class DbConfigR1 extends TomcatDataSourceConfiguration {
#Bean(name = "dsRegion1")
public DataSource dataSource() {
return super.dataSource();
}
#Bean(name = "00001")
public JdbcTemplate jdbcTemplate(DataSource dsRegion1) {
return new JdbcTemplate(dsRegion1);
}
}
When I call my service, I'll use something like this:
public AccessBeans(ServletRequest request, String enterprise_id) {
ctx = RequestContextUtils.getWebApplicationContext(request);
template = ctx.getBean(enterprise_id, JdbcTemplate.class);
}
Still open to better ways or insight into foreseeable issues, etc but this way seems to be about equivalent to my current XML based ways. Thoughts?

Resources