I have the following class
class MongoCascadeSaveEventListener extends AbstractMongoEventListener<Object> {
#Override
public void onBeforeConvert(final BeforeConvertEvent<Object> event) {
}
}
Bean definition
#Bean
public MongoCascadeSaveEventListener mongoCascadeSaveEventListener() {
return new MongoCascadeSaveEventListener();
}
onBeforeConvert is never being called.
When i check the class of MongoTemplate the event publisher is set like following
eventPublisher = new MongoMappingEventPublisher(indexCreator);
The class from spring mongo package. When i see the class i dont think the implementation is correct and that explains why listener is not invoked.
public class MongoMappingEventPublisher implements ApplicationEventPublisher {
private final MongoPersistentEntityIndexCreator indexCreator;
/**
* Creates a new {#link MongoMappingEventPublisher} for the given {#link MongoPersistentEntityIndexCreator}.
*
* #param indexCreator must not be {#literal null}.
*/
public MongoMappingEventPublisher(MongoPersistentEntityIndexCreator indexCreator) {
Assert.notNull(indexCreator, "MongoPersistentEntityIndexCreator must not be null!");
this.indexCreator = indexCreator;
}
/*
* (non-Javadoc)
* #see org.springframework.context.ApplicationEventPublisher#publishEvent(org.springframework.context.ApplicationEvent)
*/
#SuppressWarnings("unchecked")
public void publishEvent(ApplicationEvent event) {
if (event instanceof MappingContextEvent) {
indexCreator.onApplicationEvent((MappingContextEvent<MongoPersistentEntity<?>, MongoPersistentProperty>) event);
}
}
/*
* (non-Javadoc)
* #see org.springframework.context.ApplicationEventPublisher#publishEvent(java.lang.Object)
*/
public void publishEvent(Object event) {}
}
is this a bug or am i missing something here ? Using 2.0.5.Release version of spring data mongo.
Your config looks fine and the listener should be called, MongoTemplate implements ApplicationContextAware and hence after construction it sets eventPublisher to the applicationContext
Related
My Student entity class
package com.example.entity;
import java.io.Serializable;
import javax.persistence.Id;
import org.springframework.data.mongodb.core.mapping.Document;
#Document(collection = "student")
public class StudentMongo implements Serializable {
private static final long serialVersionUID = 8764013757545132519L;
#Id
private Long id;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
My Repository
package com.example.repository;
import javax.annotation.Resource;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
import org.springframework.data.mongodb.repository.support.SimpleMongoRepository;
import org.springframework.stereotype.Repository;
import com.example.entity.StudentMongo;
#Repository
public class StudentMongoRepository extends SimpleMongoRepository<StudentMongo, Long> {
#Resource
MongoOperations mongoOperations;
public StudentMongoRepository(MongoEntityInformation<StudentMongo, Long> metadata, MongoOperations mongoOperations) {
super(metadata, mongoOperations);
}
}
My configuration class
#Configuration
#EnableMongoRepositories(basePackageClasses = {com.example.repository.StudentMongoRepository.class})
public class MongoConfiguration {
}
Spring boot application
When i try to start the application i am getting following application
2017-11-20 09:04:48.937 ERROR 23220 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.example.repository.StudentMongoRepository required a bean of type 'org.springframework.data.mongodb.repository.query.MongoEntityInformation' that could not be found.
Action:
Consider defining a bean of type 'org.springframework.data.mongodb.repository.query.MongoEntityInformation' in your configuration.
Consider defining a bean of type 'org.springframework.data.mongodb.repository.query.MongoEntityInformation' in your configuration
How to create EntityInformation bean as said by spring framework
Getting above issue while running my application . how to pass entity information
suggest me how to use SimpleMongorepository
I had the same problem and I solved externalizating the MongoEntityInformationSupport of Spring Data.
Do this:
Create theese three classes:
public final class MongoEntityInformationSupport {
private MongoEntityInformationSupport() {}
/**
* Factory method for creating {#link MongoEntityInformation}.
*
* #param entity must not be {#literal null}.
* #param idType can be {#literal null}.
* #return never {#literal null}.
*/
#SuppressWarnings("unchecked")
public static <T, ID> MongoEntityInformation<T, ID> entityInformationFor(MongoPersistentEntity<?> entity,
#Nullable Class<?> idType) {
Assert.notNull(entity, "Entity must not be null!");
MappingMongoEntityInformation<T, ID> entityInformation = new MappingMongoEntityInformation<T, ID>(
(MongoPersistentEntity<T>) entity, (Class<ID>) idType);
return ClassUtils.isAssignable(Persistable.class, entity.getType())
? new PersistableMongoEntityInformation<T, ID>(entityInformation) : entityInformation;
}
}
Ps.: Put PersistableMongoEntityInformation in the same package of MongoEntityInformationSupport
#RequiredArgsConstructor //<-- Lombok
class PersistableMongoEntityInformation<T, ID> implements MongoEntityInformation<T, ID> {
private final #NonNull
MongoEntityInformation<T, ID> delegate;
/*
* (non-Javadoc)
* #see org.springframework.data.mongodb.repository.MongoEntityInformation#getCollectionName()
*/
#Override
public String getCollectionName() {
return delegate.getCollectionName();
}
/*
* (non-Javadoc)
* #see org.springframework.data.mongodb.repository.MongoEntityInformation#getIdAttribute()
*/
#Override
public String getIdAttribute() {
return delegate.getIdAttribute();
}
/*
* (non-Javadoc)
* #see org.springframework.data.repository.core.EntityInformation#isNew(java.lang.Object)
*/
#Override
#SuppressWarnings("unchecked")
public boolean isNew(T t) {
if (t instanceof Persistable) {
return ((Persistable<ID>) t).isNew();
}
return delegate.isNew(t);
}
/*
* (non-Javadoc)
* #see org.springframework.data.repository.core.EntityInformation#getId(java.lang.Object)
*/
#Override
#SuppressWarnings("unchecked")
public ID getId(T t) {
if (t instanceof Persistable) {
return ((Persistable<ID>) t).getId();
}
return delegate.getId(t);
}
/*
* (non-Javadoc)
* #see org.springframework.data.repository.core.support.PersistentEntityInformation#getIdType()
*/
#Override
public Class<ID> getIdType() {
return delegate.getIdType();
}
/*
* (non-Javadoc)
* #see org.springframework.data.repository.core.support.EntityMetadata#getJavaType()
*/
#Override
public Class<T> getJavaType() {
return delegate.getJavaType();
}
}
I created this MongoHelper just for simplify
public class MongoHelper {
public static MongoEntityInformation getEntityInformationFor(Class clazz, Class idClazz) {
TypeInformation typeInformation = ClassTypeInformation.from(clazz);
MongoPersistentEntity mongoPersistentEntity = new BasicMongoPersistentEntity(typeInformation);
return MongoEntityInformationSupport.entityInformationFor(mongoPersistentEntity, idClazz);
}
}
Finally
You can use like this(Sample with QuerydslMongoPredicateExecutor):
public class TicketRepositoryCustomImpl extends QuerydslMongoPredicateExecutor<Ticket> implements TicketRepositoryCustom {
//The MongoOperations will be autowired
public TicketRepositoryCustomImpl(MongoOperations mongoOperations) {
super(MongoHelper.getEntityInformationFor(Ticket.class, String.class), mongoOperations);
}
#Override
public Optional<Ticket> findWithFilter(TicketFilter filter) {
BooleanBuilder builder = new BooleanBuilder();
//populate the builder
return findOne(builder.getValue());
}
}
First of all I would like to say that please DON'T USE IMPLEMENTATION CLASS INSTEAD USE AN INTERFACE.
declare an Interface and extend it from MongoRepository<T,ID>, spring will provide the implementation out-of-the-box.
#Repository
public interface StudentMongoRepository extends MongoRepository<T,ID>{
#Autowired
private MongoOperations mongoOperations;
This should work.
Try this :-
don't make it autowired just make a variable like this .
private MongoTemplate mongoTemplate;
XXService extends PagingAndSortingRepository<XX, String>{
}
----------------------------------------------------------------
#Service
public class XXXmpl extends SimpleMongoRepository<XX, String> implements XXService {
public XXImpl(MongoOperations mongoOperations) {
super(new MongoRepositoryFactory(mongoOperations).getEntityInformation(XXX.class), mongoOperations);
}
}
I was trying to use spring's eventLisnter in spring-boot 1.3.5.RELEASE.
I was wondering if there is a standard way to return saved object back, or return more information after event was processed.
I may use event as a container to set my saved object back, but I am not sure if this is the best practice, any advice will be appreciated:)
Here is the example:
public class StoreOrderEvent extends ApplicationEvent {
private OrderBean orderBean;
/**
* Create a new ApplicationEvent.
*
* #param source the object on which the event initially occurred (never {#code null})
*/
public StoreOrderEvent (Object source, OrderBean orderBean) {
super(source);
this.orderBean = orderBean;
}
public OrderBean getOrderBean() {
return this.orderBean;
}
}
#Component
public class OrderEventListener{
#Autowired
private OrderRepository orderRepository;
#Order(5000)
#TransactionalEventListener
public void processStoreOrderEvent(StoreOrderEvent event) {
OrderBean orderbean = orderRepository.save(event.getOrderBean());
// return orderBean
}
}
#Service
public class OrderService{
#Autowired
private ApplicationContext applicationContext;
public OrderBean storeOrder(OrderVO vo) {
vo -> orderBean;
applicationContext.publishEvent(new StoreOrderEvent(this, orderBean));
// get my saved orderBean
}
}
As discussed with OrangeDog on comments. it's good to use service and then post event.
or Might use service and use ServiceLocatorFactoryBean to get custom service.
Excuse me ! I have a question here. Which version of Spring is “org.springframework.session.*” ? I can't find it in Spring4.0 jar at all.
here is the class:
public abstract class AbstractSessionWebSocketMessageBrokerConfigurer<S extends ExpiringSession>
extends AbstractWebSocketMessageBrokerConfigurer {
#Autowired
#SuppressWarnings("rawtypes")
private SessionRepository sessionRepository;
#Autowired
private ApplicationEventPublisher eventPublisher;
#Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.setInterceptors(sessionRepositoryInterceptor());
}
#Override
public final void registerStompEndpoints(StompEndpointRegistry registry) {
configureStompEndpoints(new SessionStompEndpointRegistry(registry,sessionRepositoryInterceptor()));
}
/**
* Register STOMP endpoints mapping each to a specific URL and (optionally)
* enabling and configuring SockJS fallback options with a
* {#link SessionRepositoryMessageInterceptor} automatically added as an
* interceptor.
*
* #param registry
* the {#link StompEndpointRegistry} which automatically has a
* {#link SessionRepositoryMessageInterceptor} added to it.
*/
protected abstract void configureStompEndpoints(StompEndpointRegistry registry);
#Override
public void configureWebSocketTransport(
WebSocketTransportRegistration registration) {
registration.addDecoratorFactory(wsConnectHandlerDecoratorFactory());
}
#Bean
public WebSocketRegistryListener webSocketRegistryListener() {
return new WebSocketRegistryListener();
}
#Bean
public WebSocketConnectHandlerDecoratorFactory wsConnectHandlerDecoratorFactory() {
return new WebSocketConnectHandlerDecoratorFactory(eventPublisher);
}
#Bean
#SuppressWarnings("unchecked")
public SessionRepositoryMessageInterceptor<S> sessionRepositoryInterceptor() {
return new SessionRepositoryMessageInterceptor<S>(sessionRepository);
}
static class SessionStompEndpointRegistry implements StompEndpointRegistry {
private final StompEndpointRegistry registry;
private final HandshakeInterceptor interceptor;
public SessionStompEndpointRegistry(StompEndpointRegistry registry,HandshakeInterceptor interceptor) {
this.registry = registry;
this.interceptor = interceptor;
}
public StompWebSocketEndpointRegistration addEndpoint(String... paths) {
StompWebSocketEndpointRegistration endpoints = registry.addEndpoint(paths);
endpoints.addInterceptors(interceptor);
return endpoints;
}
}
}
Spring Session is a separate project: https://github.com/spring-projects/spring-session.
You should use some dependency management tool (Gradle or Maven) to have a control over artifacts for your application.
See WebScoket sample there: https://github.com/spring-projects/spring-session/tree/master/samples/websocket .
A Spring Session artifact is:
compile "org.springframework.session:spring-session:1.0.0.RC1"
How do I broadcast to all subscribers(Topic) and the specified user(Channel).
this.messagingTemplate.convertAndSend(destination, message);
this.messagingTemplate.convertAndSendToUser(userId, destination, message);
Is that correct?
What is WebSocketConnectHandlerDecoratorFactory class for?
public final class WebSocketConnectHandlerDecoratorFactory implements WebSocketHandlerDecoratorFactory {
private static final Log logger = LogFactory.getLog(WebSocketConnectHandlerDecoratorFactory.class);
private final ApplicationEventPublisher eventPublisher;
/**
* Creates a new instance
*
* #param eventPublisher the {#link ApplicationEventPublisher} to use. Cannot be null.
*/
public WebSocketConnectHandlerDecoratorFactory(ApplicationEventPublisher eventPublisher) {
Assert.notNull(eventPublisher, "eventPublisher cannot be null");
this.eventPublisher = eventPublisher;
}
#Override
public WebSocketHandler decorate(WebSocketHandler handler) {
return new SessionWebSocketHandler(handler);
}
private final class SessionWebSocketHandler extends WebSocketHandlerDecorator {
public SessionWebSocketHandler(WebSocketHandler delegate) {
super(delegate);
}
#Override
public void afterConnectionEstablished(WebSocketSession wsSession)
throws Exception {
super.afterConnectionEstablished(wsSession);
publishEvent(new SessionConnectEvent(this,wsSession));
}
private void publishEvent(ApplicationEvent event) {
try {
eventPublisher.publishEvent(event);
}
catch (Throwable ex) {
logger.error("Error publishing " + event + ".", ex);
}
}
}
}
Correct.
See its JavaDocs:
/**
* Ensures that a {#link SessionConnectEvent} is published in
* {#link WebSocketHandler#afterConnectionEstablished(WebSocketSession)}. This
* is necessary so that the {#link WebSocketSession} can be mapped to the
* corresponding Spring {#link Session} to terminate any
* {#link WebSocketSession} associated with a Spring {#link Session} that was
* destroyed.
*
* #author Rob Winch
* #since 1.0
*
* #see WebSocketRegistryListener
*/
We are evaluating CodePro analytix to generate jUnits. We are working on a web project in spring3.0. As of now CodePro is generating useless jUnits. It generates identical testcase. ( I have already specified spring-test.jar as the manual suggests ).
If you have used this tool for jUnit generation in Spring project, then please help. I assume we have to specify our spring-configuration xml somewhere or else how it will get to know about DI. Also, we might require to mock few of the required object, not sure though.
Once done the codepro plugin setup, Right Click on the class or package ->select generate Junit test cases.
It will generate test class for your class. Then inside setup method you have to set the spring config XML.
ServiceFacadeImpl.Java:
public class ServiceFacadeImpl implements ServiceFacade {
private ServiceDAO serviceDAO;
#Override
public ServiceVO getService(int serviceId) {
return (ServiceVO) serviceDAO.getById(serviceId);
}
#Override
public List<ServiceVO> getServices() {
String criteria = " WHERE activeSwitch='Y' ORDER BY lastUpdatedDt DESC";
return (List<ServiceVO>) serviceDAO.getAll(criteria);
}
/**
* #return the serviceDAO
*/
public ServiceDAO getServiceDAO() {
return serviceDAO;
}
/**
* #param serviceDAO
* the serviceDAO to set
*/
public void setServiceDAO(ServiceDAO serviceDAO) {
this.serviceDAO = serviceDAO;
}
}
*Codepro Generated Class *
ServiceFacadeImplTest.java:
public class ServiceFacadeImplTest {
private ServiceFacadeImpl serviceFacadeImpl;
ServiceFacadeImpl fixture = null;
/**
* Run the ServiceVO getService(int) method test.
*
* #throws Exception
*
* #generatedBy CodePro at 7/7/13 10:34 PM
*/
#Test
public void testGetService_1() throws Exception {
List<ServiceVO> result = fixture.getServices();
int serviceId = 0;
ServiceVO result1 = fixture.getService(1);
assertNotNull(result1);
}
/**
* Run the List<ServiceVO> getServices() method test.
*
* #throws Exception
*
* #generatedBy CodePro at 7/7/13 10:34 PM
*/
#Test
public void testGetServices_1() throws Exception {
List<ServiceVO> result = fixture.getServices();
assertNotNull(result);
}
/**
* Perform pre-test initialization.
*
* #throws Exception
* if the initialization fails for some reason
*
* #generatedBy CodePro at 7/7/13 10:34 PM
*/
#SuppressWarnings("resource")
#Before
public void setUp() throws Exception {
this.setServiceFacadeImpl((ServiceFacadeImpl) new ClassPathXmlApplicationContext(
"applicationContext-facade.xml").getBean("serviceFacade"));
fixture = this.getServiceFacadeImpl();
}
/**
* Perform post-test clean-up.
*
* #throws Exception
* if the clean-up fails for some reason
*
* #generatedBy CodePro at 7/7/13 10:34 PM
*/
#After
public void tearDown() throws Exception {
// Add additional tear down code here
}
/**
* Launch the test.
*
* #param args
* the command line arguments
*
* #generatedBy CodePro at 7/7/13 10:34 PM
*/
public static void main(String[] args) {
new org.junit.runner.JUnitCore().run(ServiceFacadeImplTest.class);
}
/**
* #return the serviceFacadeImpl
*/
public ServiceFacadeImpl getServiceFacadeImpl() {
return serviceFacadeImpl;
}
/**
* #param serviceFacadeImpl
* the serviceFacadeImpl to set
*/
public void setServiceFacadeImpl(ServiceFacadeImpl serviceFacadeImpl) {
this.serviceFacadeImpl = serviceFacadeImpl;
}
}
In the setup() method, we have to load the spring config xml, the above one i have loaded applicationContext-facade.xml