MyBatis version
3.5.4
Database vendor and version
MySQL 5.7.14
Test case or example project
public static final String URL = "jdbc:mysql://localhost:3306/myTest?useUnicode=true&characterEncoding=UTF-8&useSSL=false";
public static final String Driver = "com.mysql.cj.jdbc.Driver";
public static final String User_Name = "root";
public static final String Password = "";
public static void main(String[] args) {
DataSource dataSource = new PooledDataSource(Driver,URL, User_Name,Password);
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.select("selectCount",resultContext -> {
System.out.println(resultContext.getResultCount());
System.out.println(resultContext.getResultObject());
});
Object c = sqlSession.selectOne("selectCount");
System.out.println(c);
}
public interface BlogMapper {
#Select("select count(*) from datas")
public int selectCount();
}
Steps to reproduce
Expected result
Object c = sqlSession.selectOne("selectCount");
selectOne function should retuen result ,but return null.
Actual result
sqlSession.selectOne("selectCount"); return null
I'm writing some message consumer for an AWS SQS and want to validate the received message by using the javax.validation.constraints annotations.
Unfortunately I had to find out, that the used PayloadArgumentResolver of the spring-cloud-aws-messaging dependency uses a NoOpValidator.
So I tried to inject my own HandlerMethodArgumentResolver for the payload.
#Bean
public QueueMessageHandlerFactory queueMessageHandlerFactory(
final ObjectMapper objectMapper, final Validator hibernateValidator) {
final MappingJackson2MessageConverter jacksonMessageConverter =
new MappingJackson2MessageConverter();
jacksonMessageConverter.setSerializedPayloadClass(String.class);
jacksonMessageConverter.setStrictContentTypeMatch(true);
jacksonMessageConverter.setObjectMapper(objectMapper);
final QueueMessageHandlerFactory factory = new QueueMessageHandlerFactory();
final List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>();
argumentResolvers.add(new HeaderMethodArgumentResolver(null, null));
argumentResolvers.add(new HeadersMethodArgumentResolver());
argumentResolvers.add(new NotificationSubjectArgumentResolver());
argumentResolvers.add(new AcknowledgmentHandlerMethodArgumentResolver("Acknowledgment"));
argumentResolvers.add(new VisibilityHandlerMethodArgumentResolver("Visibility"));
final PayloadArgumentResolver payloadArgumentResolver =
new PayloadArgumentResolver(jacksonMessageConverter, hibernateValidator);
argumentResolvers.add(payloadArgumentResolver);
factory.setArgumentResolvers(argumentResolvers);
return factory;
}
So far so good and at first sight, it works well...
BUT as you can see I had to add the already in QueueMessageHandler existing argument resolvers as well to resolve the headers via #Headers/#Header of the message, too.
#SqsListener(
value = "queue",
deletionPolicy = SqsMessageDeletionPolicy.ON_SUCCESS)
public void consume(
#Payload #Validated final QueueMessage queueMessage,
#Headers final Map<String,Object> headers) {
}
When I only add my PayloadArgumentResolver with the hibernate validator, it will be also used to resolve the headers, doh!
Is there any pretty solution for this or should I open an issue at spring-cloud-aws? I just want my payload to be validated via annotations :(
I don't think this is the best awswer but I have a working sample project that have this type of validation: https://github.com/Haple/sqslistener
#Data
#RequiredArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
#NoArgsConstructor(access = AccessLevel.PRIVATE, force = true)
public class EventDTO {
#NotNull(message = "foo is mandatory")
private final String foo;
#NotNull(message = "bar is mandatory")
private final String bar;
}
#Slf4j
#Service
#AllArgsConstructor
public class SampleListener {
#SqsListener("test_queue")
public void execute(final #Valid #Payload EventDTO event) {
log.info("OK: {}", event);
}
}
#Configuration
public class MessageHandler {
#Bean
QueueMessageHandler queueMessageHandler(final AmazonSQSAsync amazonSQSAsync,
final MessageConverter messageConverter,
final Validator validator) {
final QueueMessageHandlerFactory queueMessageHandlerFactory = new QueueMessageHandlerFactory();
final PayloadMethodArgumentResolver payloadMethodArgumentResolver = new PayloadMethodArgumentResolver(messageConverter, validator);
queueMessageHandlerFactory.setArgumentResolvers(Collections.singletonList(payloadMethodArgumentResolver));
queueMessageHandlerFactory.setAmazonSqs(amazonSQSAsync);
queueMessageHandlerFactory.setMessageConverters(Collections.singletonList(messageConverter));
return queueMessageHandlerFactory.createQueueMessageHandler();
}
}
I am trying to write test case for Account controller class. Account controller is depends on Account service class so I am using mockito. In Account Service I am using Querydsl for creating dynamic query for implementing search filter.
I tried to write test case like below. In that test class I am able to receive query result in array format. But I am getting empty body and because of that getting this error java.lang.AssertionError: No value at JSON path "$[0].sClientAcctId"
Can any one tell me why I am getting empty body?
AccountController
#GetMapping("/findAccountData")
public ResponseEntity<List<Tuple>> populateGridViews(#RequestParam(value="sClientAcctId",required=false) String sClientAcctId,
#RequestParam(value="sAcctDesc",required=false) String sAcctDesc,
#RequestParam(value="sInvestigatorName",required=false)String sInvestigatorName,
#RequestParam(value="sClientDeptId",required=false) String sClientDeptId) throws Exception {
return ResponseEntity.ok(accService.populateGridViews(sClientAcctId, sAcctDesc,sInvestigatorName,sClientDeptId));
}
TestAccountControllerGrid
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class TestAccountControllerGrid {
#Autowired
private MockMvc mockMvc;
#Mock
private AccountService accountService;
#InjectMocks
private AccountController accountController;
#Autowired
EntityManager em;
#Value("${InstituteIdentifier}")
private String instituteIdentifier;
#Test
#Transactional
public void populateGridViewsTest() throws Exception {
String sClientAcctId ="1110720";
String sAcctDesc ="DR DE DUVE";
String sInvestigatorName ="Acquaviva, Adelaide";
String sClientDeptId ="110720";
Department departmentObject = new Department();
departmentObject.setsClientDeptId("110720");
departmentObject.setsDeptName("de Duve Laboratory");
departmentObject.setnInstId(60);
departmentObject.setbIsLocked(false);
departmentObject.setbAlternateJointusePercentage(true);
Investigator investigatorObject= new Investigator();
investigatorObject.setsInvestigatorName("Acquaviva, Adelaide");
investigatorObject.setnInstId(60);
Account accountObject = new Account();
accountObject.setsAcctDesc(" ASTRALIS LTD");
accountObject.setsClientAcctId("5400343");
accountObject.setsLocation("A");
accountObject.setnAccountCPCMappingId(123);
accountObject.setnAgencyId(20356);
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
accountObject.setdEndDate(timestamp );
accountObject.setDepartment(departmentObject);
accountObject.setInvestigator(investigatorObject);
em.merge(accountObject);
QAccount account = QAccount.account;
JPAQuery<Tuple> query = new JPAQuery<Tuple>(em);
List<Tuple> result = query.select(account.sAcctDesc, account.sClientAcctId,account.sLocation)
.from(account).fetch();
System.out.println("Query Result = "+ result);
Mockito.when(accountService.populateGridViews(sClientAcctId, sAcctDesc, sInvestigatorName, sClientDeptId))
.thenReturn(result);
mockMvc.perform(get("/spacestudy/"+instituteIdentifier+"/admin/account/findAccountData")
.param("sClientAcctId", "1110720")
.param("sAcctDesc", "DR DE DUVE")
.param("sInvestigatorName", "Acquaviva, Adelaide")
.param("sClientDeptId", "110720")
.accept(MediaType.APPLICATION_JSON)
)
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].sAcctDesc", is("DR DE DUVE")))
.andExpect(jsonPath("$[0].sClientAcctId", is("1110720")))
.andExpect(jsonPath("$[0].sLocation", is("ON")))
.andExpect(jsonPath("$[0].department.sDeptName", is("de Duve Laboratory")))
.andExpect(jsonPath("$[0].investigator.sInvestigatorName", is("Acquaviva, Adelaide")));
//Mockito.verify(accountService).populateGridViews(sClientAcctId, sAcctDesc, sInvestigatorName, sClientDeptId);
}
I have an image upload/store application in which I have a User entity having multiple related images(List<Image> images using OneToMany relationship). I am iterating images of the user in session using struts iterator tag in Home.jsp
<s:iterator value="#session['user'].images" status="itStatus">
<s:property value="imageid"/>
<s:property value="name"/>
<s:url action="GetImageAction" var="imgUrl">
<s:param name="imageId" value="imageid"></s:param>
</s:url>
<li>
<img src="<s:property value="#imgUrl"/>"/>
</li>
</s:iterator>
The upload form is on the same page so when the user logs in, he can see the images he has already uploaded & can also upload new images.
Here is my problem. When a new image is uploaded, the same page refreshes to show his images but the recently uploaded image does not get displayed(appears as broken) but I am able to see all previously uploaded images. This is because the imageId field of Image is having the value 0 in this case instead of the correct id. GetImageAction action sets the inputstream from the image using the param imageId
Here is the Image class:
#Entity(name="Images")
public class Image implements Serializable {
private long imageid;
private String name;
private byte[] image;
private static final long serialVersionUID = 1L;
public Image() {
super();
}
public Image(String name, byte[] image) {
super();
this.name = name;
this.image = image;
}
#Id
#GeneratedValue
#Column(name="Id")
public long getImageid() {
return this.imageid;
}
public void setImageid(long id) {
this.imageid = id;
}
...
}
Now I am guessing this is because the new Image object iterated is having the default long value 0 instead of the generated Id (I am able to access other fields' values like name). Why is this? Since the image is already persisted by the time the result is displayed, shouldn't the Id value be retrieved correctly? What am I doing wrong here?
Please help. I feel I may be missing something simple here but it just wouldn't get solved.
Edit:
UserAddImageAction
public class UserAddImageAction implements SessionAware {
private User user;
private Map session;
private File photo;
private String photoContentType;
private String photoFileName;
public String execute() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("StrTest1");
EntityManager em = emf.createEntityManager();
EntityTransaction etx = em.getTransaction();
try {
BufferedInputStream i = new BufferedInputStream(new FileInputStream(photo));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int c;
while((c=i.read()) != -1) {
baos.write(c);
}
user = (User) session.get("user");
user.getImages().add(new Image(photoFileName, baos.toByteArray()));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
etx.begin();
em.merge(user);
etx.commit();
em.close();
emf.close();
session.put("user", user);
return "SUCCESS";
}
...
I try to configure a spring exception handler for a rest controller that is able to render a map to both xml and json based on the incoming accept header. It throws a 500 servlet exception right now.
This works, it picks up the home.jsp:
#ExceptionHandler(IllegalArgumentException.class)
public String handleException(final Exception e, final HttpServletRequest request, Writer writer)
{
return "home";
}
This does not work:
#ExceptionHandler(IllegalArgumentException.class)
public #ResponseBody Map<String, Object> handleException(final Exception e, final HttpServletRequest request, Writer writer)
{
final Map<String, Object> map = new HashMap<String, Object>();
map.put("errorCode", 1234);
map.put("errorMessage", "Some error message");
return map;
}
In the same controller mapping the response to xml or json via the respective converter works:
#RequestMapping(method = RequestMethod.GET, value = "/book/{id}", headers = "Accept=application/json,application/xml")
public #ResponseBody
Book getBook(#PathVariable final String id)
{
logger.warn("id=" + id);
return new Book("12345", new Date(), "Sven Haiges");
}
Your method
#ExceptionHandler(IllegalArgumentException.class)
public #ResponseBody Map<String, Object> handleException(final Exception e, final HttpServletRequest request, Writer writer)
does not work because it has the wrong return type. #ExceptionHandler methods have only two valid return types:
String
ModelAndView.
See http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html for more information. Here's the specific text from the link:
The return type can be a String, which
is interpreted as a view name or a
ModelAndView object.
In response to the comment
Thanx, seems I overread this. That's
bad... any ideas how to provides
exceptions automatically in xml/json
format? – Sven Haiges 7 hours ago
Here's what I've done (I've actually done it in Scala so I'm not sure if the syntax is exactly correct, but you should get the gist).
#ExceptionHandler(Throwable.class)
#ResponseBody
public void handleException(final Exception e, final HttpServletRequest request,
Writer writer)
{
writer.write(String.format(
"{\"error\":{\"java.class\":\"%s\", \"message\":\"%s\"}}",
e.getClass(), e.getMessage()));
}
Thanx, seems I overread this. That's bad... any ideas how to provides
exceptions automatically in xml/json format?
New in Spring 3.0 MappingJacksonJsonView can be utilized to achieve that:
private MappingJacksonJsonView jsonView = new MappingJacksonJsonView();
#ExceptionHandler(Exception.class)
public ModelAndView handleAnyException( Exception ex )
{
return new ModelAndView( jsonView, "error", new ErrorMessage( ex ) );
}
This seems ilke a confirmed Bug (SPR-6902
#ResponseBody does not work with #ExceptionHandler)
https://jira.springsource.org/browse/SPR-6902
Fixed in 3.1 M1 though...
The following could be a workaround if you are using message converters to marshall error objects as the response content
#ExceptionHandler(IllegalArgumentException.class)
public String handleException(final Exception e, final HttpServletRequest request)
{
final Map<String, Object> map = new HashMap<String, Object>();
map.put("errorCode", 1234);
map.put("errorMessage", "Some error message");
request.setAttribute("error", map);
return "forward:/book/errors"; //forward to url for generic errors
}
//set the response status and return the error object to be marshalled
#SuppressWarnings("unchecked")
#RequestMapping(value = {"/book/errors"}, method = {RequestMethod.POST, RequestMethod.GET})
public #ResponseBody Map<String, Object> showError(HttpServletRequest request, HttpServletResponse response){
Map<String, Object> map = new HashMap<String, Object>();
if(request.getAttribute("error") != null)
map = (Map<String, Object>) request.getAttribute("error");
response.setStatus(Integer.parseInt(map.get("errorCode").toString()));
return map;
}
I am using Spring 3.2.4. My solution to the problem was to make sure that the object I was returning from the exception handler had getters.
Without getters Jackson was unable to serialize the object to JSON.
In my code, for the following ExceptionHandler:
#ExceptionHandler(RuntimeException.class)
#ResponseBody
public List<ErrorInfo> exceptionHandler(Exception exception){
return ((ConversionException) exception).getErrorInfos();
}
I needed to make sure my ErrorInfo object had getters:
package com.pelletier.valuelist.exception;
public class ErrorInfo {
private int code;
private String field;
private RuntimeException exception;
public ErrorInfo(){}
public ErrorInfo(int code, String field, RuntimeException exception){
this.code = code;
this.field = field;
this.exception = exception;
}
public int getCode() {
return code;
}
public String getField() {
return field;
}
public String getException() {
return exception.getMessage();
}
}
AnnotationMethodHandlerExceptionResolver also need MappingJacksonHttpMessageConverter
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver">
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</list>
</property>
</bean>
<bean id="jacksonObjectMapper"
class="iacm.cemetery.framework.web.servlet.rest.JacksonObjectMapper" />
I faced the similar issue, this problem occurs when your Controller method return type and ExceptionHandler return types are not same. Make sure you have exactly same return types.
Controller method:
#RequestMapping(value = "/{id}", produces = "application/json", method = RequestMethod.POST)
public ResponseEntity<?> getUserById(#PathVariable String id) throws NotFoundException {
String response = userService.getUser(id);
return new ResponseEntity(response, HttpStatus.OK);
}
Advice method:
#ExceptionHandler(NotFoundException.class)
public ResponseEntity<?> notFoundException(HttpServletRequest request, NotFoundException e) {
ExceptionResponse response = new ExceptionResponse();
response.setSuccess(false);
response.setMessage(e.getMessage());
return new ResponseEntity(response, HttpStatus.NOT_FOUND);
}
As you can see return types in both the classes are same ResponseEntity<?>.