I'm trying a new development method.
In mybatis3, I write mapper.java and mapper.xml usually.
I know, the sql statements is corresponded by sqlId(namespace+id).
I want to execute the sql statement like this :
SqlSession sqlSession = sessionFactory.openSession();
return sqlSession.selectList(sqlId, param);
but I get a error:
Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for mapper.JinBoot.test
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:150)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141)
at cn.tianyustudio.jinboot.dao.BaseDao.select(BaseDao.java:20)
at cn.tianyustudio.jinboot.service.BaseService.select(BaseService.java:10)
at cn.tianyustudio.jinboot.controller.BaseController.test(BaseController.java:21)
here is my BaseDao.java
public class BaseDao {
private static SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
public static List<Map> select(String sqlId, Map param) {
try {
factoryBean.setDataSource(new DruidDataSource());
SqlSessionFactory sessionFactory = factoryBean.getObject();
SqlSession sqlSession = sessionFactory.openSession();
return sqlSession.selectList(sqlId, param);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
here is UserMapper.xml
<mapper namespace="mapper.JinBoot">
<select id="test" parameterType="hashMap" resultType="hashMap">
select * from user
</select>
</mapper>
the application.properties
mybatis.mapperLocations=classpath:mapper/*.xml
I start the project, the send a http request, after controller and service ,the param 'sqlId' in BaseDao is 'mapper.JinBoot.test' (see error info).
In method 'BaseDao.select', both the parameter and the result type is Map.
So I don't want to create UserMapper.java, I want try it.
How can I resolve it? What's the malpractice of this way?
This does not work because spring boot creates its own SqlSessionFactory. And the option in application.properties that specifies where mappers should be looked for is only set for that SqlSessionFactory. You are creating unrelated session factory in your DAO and it does not know where to load mappers definition.
If you want to make it work you need that you DAO is spring managed so that you can inject mybatis session factory into it and use it in select. This would also require that you convert select into non static method.
As I understand you want to have only one method in you base DAO class and use it in individual specific DAO classes. I would say it makes little sense. If the method returns Map there will be some place that actually maps this generic type to some application specific types. This would probably be in the child DAOs. So you still need to create the API of the child DAO with the signature that uses some input parameters and returns some domain objects. And that's exactly what you want to avoid by not creating mybatis mapper classes.
The thing is that you can treat your mytabis mappers as DAOs. That is you mappers would be your DAOs. And you don't need another layer. As I understand now you have two separate layers - DAO and mappers and you want to remove boilerplate code. I think it is better to remove DAO classes. They are real boilerplate and mybatis mapper can serve as DAO perfectly. You inject it directly to you service and service depends only on the mapper class. The logic of the mapping is in the mapper xml file. See also answer to this question Can Spring DAO be merged into Service layer?
In the project I am assigned to do, it involves reading details of products from Info Engine using a Java Interface. How to do it? Suggest me tutorials or books or anything that helps me get started.
You can do that by implementing ComponentDataBuilder and that will return
a well populated IeTaskInfo object. It takes the action name as the constructor which gives information of the
task that need to be executed to get the data For example, the following code
snippet demonstrates the use of the “jca-Search” task .
public class MyDataBuilderWithIETask implements ComponentDataBuilder {
#Override
public Object buildComponentData(ComponentConfig config,
ComponentParams params) throws WTException {
//pass the task name as constructor
IeTaskInfo taskInfo = new IeTaskInfo("jca-Search");
……..
return taskInfo;
}
}
For more info please refer
Info*Engine User's Guide
Windchill Adapter Guide (Info*Engine)
I have a pretty standard MVC setup with Spring Data JPA Repositories for my DAO layer, a Service layer that handles Transactional concerns and implements business logic, and a view layer that has some lovely REST-based JSON endpoints.
My question is around wholesale adoption of Java 8 Streams into this lovely architecture: If all of my DAOs return Streams, my Services return those same Streams (but do the Transactional work), and my Views act on and process those Streams, then by the time my Views begin working on the Model objects inside my Streams, the transaction created by the Service layer will have been closed. If the underlying data store hasn't yet materialized all of my model objects (it is a Stream after all, as lazy as possible) then my Views will get errors trying to access new results outside of a transaction. Previously this wasn't a problem because I would fully materialize results into a List - but now we're in the brave new world of Streams.
So, what is the best way to handle this? Fully materialize the results inside of the Service layer as a List and hand them back? Have the View layer hand the Service layer a completion block so further processing can be done inside of a transaction?
Thanks for the help!
In thinking through this, I decided to try the completion block solution I mentioned in my question. All of my service methods now have as their final parameter a results transformer that takes the Stream of Model objects and transforms it into whatever resulting type is needed/requested by the View layer. I'm pleased to report it works like a charm and has some nice side-effects.
Here's my Service base class:
public class ReadOnlyServiceImpl<MODEL extends AbstractSyncableEntity, DAO extends AbstractSyncableDAO<MODEL>> implements ReadOnlyService<MODEL> {
#Autowired
protected DAO entityDAO;
protected <S> S resultsTransformer(Supplier<Stream<MODEL>> resultsSupplier, Function<Stream<MODEL>, S> resultsTransform) {
try (Stream<MODEL> results = resultsSupplier.get()) {
return resultsTransform.apply(results);
}
}
#Override
#Transactional(readOnly = true)
public <S> S getAll(Function<Stream<MODEL>, S> resultsTransform) {
return resultsTransformer(entityDAO::findAll, resultsTransform);
}
}
The resultsTransformer method here is a gentle reminder for subclasses to not forget about the try-with-resources pattern.
And here is an example Controller calling in to the service base class:
public abstract class AbstractReadOnlyController<MODEL extends AbstractSyncableEntity,
DTO extends AbstractSyncableDTOV2,
SERVICE extends ReadOnlyService<MODEL>>
{
#Autowired
protected SERVICE entityService;
protected Function<MODEL, DTO> modelToDTO;
protected AbstractReadOnlyController(Function<MODEL, DTO> modelToDTO) {
this.modelToDTO = modelToDTO;
}
protected List<DTO> modelStreamToDTOList(Stream<MODEL> s) {
return s.map(modelToDTO).collect(Collectors.toList());
}
// Read All
protected List<DTO> getAll(Optional<String> lastUpdate)
{
if (!lastUpdate.isPresent()) {
return entityService.getAll(this::modelStreamToDTOList);
} else {
Date since = new TimeUtility(lastUpdate.get()).getTime();
return entityService.getAllUpdatedSince(since, this::modelStreamToDTOList);
}
}
}
I think it's a pretty neat use of generics to have the Controllers dictate the return type of the Services via the Java 8 lambda's. While it's strange for me to see the Controller directly returning the result of a Service call, I do appreciate how tight and expressive this code is.
I'd say this is a net positive for attempting a wholesale switch to Java 8 Streams. Hopefully this helps someone with a similar question down the road.
I have a method in my #Transaction enabled class which is getting invoked from outside class using java reflection. Unfortunately Spring Transaction is not working inside this method.
Class looks something like below:
#Transactional
public class CartServiceImpl implements CartService {
#Autowired
AnnotatedMethodInvoker annotatedMethodInvoker;
#Override
#VersionedParent
public BasicResponse addCartItem(AddCartItemRequest addCartItemRequest) throws Exception{
String currentMethodName = Thread.currentThread().getStackTrace()[1].getMethodName();
return (BasicResponse)annotatedMethodInvoker.invoke(this, currentMethodName, addCartItemRequest, AddCartItemRequest.class);
}
#VersionedMethod(parentMethod="addCartItem", minimumVersion=Constants.BUILD_VERSION_1_0_1, description="Added Epoch")
private BasicResponse addCartItemWithEpoch(AddCartItemRequest addCartItemRequest){
/***** Implementation detail goes here *****/
}
#VersionedMethod(parentMethod="addCartItem", minimumVersion=Constants.BUILD_VERSION_1_0_2, description="Added Cart filter here")
private BasicResponse addCartItemWithCartFilter(AddCartItemRequest addCartItemRequest){
/***** Implementation detail goes here *****/
}
}
In the AnnotatedMethodInvoker class's invoke() method I am invoking 1 of the two private methods addCartItemWithEpoch() & addCartItemWithCartFilter().
The problem is that when a RuntimeException is occurring, the Transaction is still getting committed, which essentially means that Spring Transaction is not working in my private method.
Surprizingly the below statement returns true if I put it inside my private method:
TransactionSynchronizationManager.isActualTransactionActive()
My application is currently using Spring AOP transaction throughout and it works seamlessly. application-config.xml snippet below:
<context:annotation-config />
<context:component-scan base-package="com.apraxalpha.dealernews" />
<tx:annotation-driven />
I have read this blog which suggests using AspectJ based Transaction over Spring AOP Transaction approach. I am not really confident about this, because my entire application is otherwise using Spring AOP based Transaction. now just for 1 single implementation change, I don't want to change everything to AspectJ transaction.
1) Is there any such middle path to have both the approaches in my application ?
2) Is there any other way to have Transaction in my private method getting invoked using java reflection?
Went through several other posts on similar problem :
1) Spring Transaction not working while calling private method of a Spring Bean class or
2) calling a method from another method in same class
Seems like either you use AspectJ instead of Spring AOP to call the bean class methods
OR
If you don't want to use AspectJ and stick to Spring AOP then a simple refatoring of the class will solve the problem as below:
In the question the method public method addCartItem and the actual implementation methods(which are actually having the implementation code) are all in the same bean class.
Consider creating a delegator class as a layer above this bean class and put the public method addCartItem in that class. Then make the both private methods as public and try to call the bean class methods from the delegator method.
I have multiple classes annotated with #ControllerAdvice, each with an #ExceptionHandler method in.
One handles Exception with the intention that if no more specific handler is found, this should be used.
Sadly Spring MVC appears to be always using the most generic case (Exception) rather than more specific ones (IOException for example).
Is this how one would expect Spring MVC to behave? I'm trying to emulate a pattern from Jersey, which assesses each ExceptionMapper (equivalent component) to determine how far the declared type that it handles is from the exception that has been thrown, and always uses the nearest ancestor.
Is this how one would expect Spring MVC to behave?
As of Spring 4.3.7, here's how Spring MVC behaves: it uses HandlerExceptionResolver instances to handle exceptions thrown by handler methods.
By default, the web MVC configuration registers a single HandlerExceptionResolver bean, a HandlerExceptionResolverComposite, which
delegates to a list of other HandlerExceptionResolvers.
Those other resolvers are
ExceptionHandlerExceptionResolver
ResponseStatusExceptionResolver
DefaultHandlerExceptionResolver
registered in that order. For the purpose of this question we only care about ExceptionHandlerExceptionResolver.
An AbstractHandlerMethodExceptionResolver that resolves exceptions
through #ExceptionHandler methods.
At context initialization, Spring will generate a ControllerAdviceBean for each #ControllerAdvice annotated class it detects. The ExceptionHandlerExceptionResolver will retrieve these from the context, and sort them using using AnnotationAwareOrderComparator which
is an extension of OrderComparator that supports Spring's Ordered
interface as well as the #Order and #Priority annotations, with an
order value provided by an Ordered instance overriding a statically
defined annotation value (if any).
It'll then register an ExceptionHandlerMethodResolver for each of these ControllerAdviceBean instances (mapping available #ExceptionHandler methods to the exception types they're meant to handle). These are finally added in the same order to a LinkedHashMap (which preserves iteration order).
When an exception occurs, the ExceptionHandlerExceptionResolver will iterate through these ExceptionHandlerMethodResolver and use the first one that can handle the exception.
So the point here is: if you have a #ControllerAdvice with an #ExceptionHandler for Exception that gets registered before another #ControllerAdvice class with an #ExceptionHandler for a more specific exception, like IOException, that first one will get called. As mentioned earlier, you can control that registration order by having your #ControllerAdvice annotated class implement Ordered or annotating it with #Order or #Priority and giving it an appropriate value.
Sotirios Delimanolis was very helpful in his answer, on further investigation we found that, in spring 3.2.4 anyway, the code that looks for #ControllerAdvice annotations also checks for the presence of #Order annotations and sorts the list of ControllerAdviceBeans.
The resulting default order for all controllers without the #Order annotation is Ordered#LOWEST_PRECEDENCE which means if you have one controller that needs to be the lowest priority then ALL your controllers need to have a higher order.
Here's an example showing how to have two exception handler classes with ControllerAdvice and Order annotations that can serve appropriate responses when either a UserProfileException or RuntimeException occurs.
class UserProfileException extends RuntimeException {
}
#ControllerAdvice
#Order(Ordered.HIGHEST_PRECEDENCE)
class UserProfileExceptionHandler {
#ExceptionHandler(UserProfileException)
#ResponseBody
ResponseEntity<ErrorResponse> handleUserProfileException() {
....
}
}
#ControllerAdvice
#Order(Ordered.LOWEST_PRECEDENCE)
class DefaultExceptionHandler {
#ExceptionHandler(RuntimeException)
#ResponseBody
ResponseEntity<ErrorResponse> handleRuntimeException() {
....
}
}
See ControllerAdviceBean#initOrderFromBeanType()
See ControllerAdviceBean#findAnnotatedBeans()
See ExceptionHandlerExceptionResolver#initExceptionHandlerAdviceCache()
Enjoy!
The order of exception handlers can be changed using the #Order annotation.
For example:
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.web.bind.annotation.ControllerAdvice;
#ControllerAdvice
#Order(Ordered.HIGHEST_PRECEDENCE)
public class CustomExceptionHandler {
//...
}
#Order's value can be any integer.
I also found in the documentation that :
https://docs.spring.io/spring-framework/docs/4.3.4.RELEASE/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.html#getExceptionHandlerMethod-org.springframework.web.method.HandlerMethod-java.lang.Exception-
ExceptionHandlerMethod
protected ServletInvocableHandlerMethod
getExceptionHandlerMethod(HandlerMethod handlerMethod,
Exception exception)
Find an #ExceptionHandler method for the given
exception. The default implementation searches methods in the class
hierarchy of the controller first and if not found, it continues
searching for additional #ExceptionHandler methods assuming some
#ControllerAdvice Spring-managed beans were detected. Parameters:
handlerMethod - the method where the exception was raised (may be
null) exception - the raised exception Returns: a method to handle the
exception, or null
So this means that if you want to solve this issue, you will need to add your specific exception handler within the controller throwing those exception. ANd to define one and only ControllerAdvice handling the Global default exception handler.
This simplies the process and we don't need the Order annotation to handle the problem.
you can also use a number value, like below
#Order(value = 100)
Lower values have higher priority. The default value is * {#code
Ordered.LOWEST_PRECEDENCE},indicating lowest priority (losing to any
other * specified order value)
Important Class to be handled :
**#Order(Ordered.HIGHEST_PRECEDENCE)**
public class FunctionalResponseEntityExceptionHandler {
private final Logger logger = LoggerFactory.getLogger(FunctionalResponseEntityExceptionHandler.class);
#ExceptionHandler(EntityNotFoundException.class)
public final ResponseEntity<Object> handleFunctionalExceptions(EntityNotFoundException ex, WebRequest request)
{
logger.error(ex.getMessage() + " " + ex);
ExceptionResponse exceptionResponse= new ExceptionResponse(new Date(), ex.getMessage(),
request.getDescription(false),HttpStatus.NOT_FOUND.toString());
return new ResponseEntity<>(exceptionResponse, HttpStatus.NOT_FOUND);
}
}
Other Exceptions with Low priority
#ControllerAdvice
public class GlobalResponseEntityExceptionHandler extends ResponseEntityExceptionHandler
{
private final Logger logger = LoggerFactory.getLogger(GlobalResponseEntityExceptionHandler.class);
#ExceptionHandler(Exception.class)
public final ResponseEntity<Object> handleAllException(Exception ex, WebRequest request)
{
logger.error(ex.getMessage()+ " " + ex);
ExceptionResponse exceptionResponse= new ExceptionResponse(new Date(), ex.toString(),
request.getDescription(false),HttpStatus.INTERNAL_SERVER_ERROR.toString());
}
}
There's a similar situation convered in the excellent "Exception Handling in Spring MVC" post on the Spring blog, in the section entitled Global Exception Handling. Their scenario involves checking for ResponseStatus annotations registered on the exception class, and if present, rethrowing the exception to let the framework handle them. You might be able to use this general tactic - try to determine if there is a might be a more appropriate handler out there and rethrowing.
Alternatively, there's some other exception handling strategies covered that you might look at instead.
If you want separate your exception handlers(like me), you can use #Import to do this.
#ControllerAdvice
class MyCustomExceptionHandler {
...
}
#ControllerAdvice
class MyOtherCustomExceptionHandler {
...
}
#Import({MyCustomExceptionHandler.class,MyOtherCustomExceptionHandler.class})
#ControllerAdvice
#Order(Ordered.LOWEST_PRECEDENCE)
class ApplicationExceptionHandler{
//Generic exception handlers
}