Error in custom repository interface - spring-data-mongodb

I'm trying to set up my first Java application using Spring Data for MongoDB in a multi-module Maven 3 project. Here are the relevant versions:
Java 7
mongodb-win32-x86_64-2.2.0
Spring Data 1.1.1.RELEASE
Spring 3.2.0.RELEASE
I'm getting the following runtime error:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'actorFacade': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private es.mi.casetools.praetor.persistence.springdata.repositories.ActorRepository es.mi.casetools.praetor.facade.impl.DefaultActorFacade.actorRepository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'actorRepository': FactoryBean threw exception on object creation; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property insert found for type void
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:287)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1106)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:609)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:106)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:57)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:100)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:248)
at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:124)
at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:148)
... 30 more
Searching in google I found people with the same issue and it seems to be related with custom repositories.
Here is the entity I want to store as a mongo document.
public class Actor {
public enum ActorStereotype {
SYSTEM,
PERSON
}
private String id;
private String code; // unique
private ActorStereotype stereotype;
private String title; // Short title for the actor
private String description;
private String projectId; // project this actor belongs to
// getters & setters
The standard repository interface.
public interface ActorRepository extends MongoRepository<Actor, String>, ActorRepositoryCustom {
}
The custom interface (where I think the error lives).
#NoRepositoryBean
public interface ActorRepositoryCustom {
void updateSingleActor(Actor actor);
void insertActor(Actor actor);
}
The custom interface implementation.
public class ActorRepositoryCustomImpl implements ActorRepositoryCustom {
#Autowired
private MongoTemplate mongoTemplate;
#Override
public void updateSingleActor(Actor actor) {
if(actor.getId() != null)
throw new MissingIdException();
// TODO change to Spring Converter
DBObject dbo = (DBObject)mongoTemplate.getConverter().convertToMongoType(actor);
mongoTemplate.updateFirst(query(where("_id").is(actor.getId())),
Update.fromDBObject(dbo, new String[]{}),
Actor.class);
}
#Override
public void insertActor(Actor actor) {
if(actor.getId() != null)
throw new IdProvidedException();
mongoTemplate.save(actor);
}
}
And finally, the application context.
<context:annotation-config/>
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:properties/test.properties</value>
</list>
</property>
</bean>
<!-- mongodb configuration -->
<mongo:repositories base-package="es.mi.casetools.praetor.persistence.springdata.repositories"
mongo-template-ref="mongoTemplate" repository-impl-postfix="Impl">
<repository:exclude-filter type="annotation" expression="org.springframework.data.repository.NoRepositoryBean"/>
</mongo:repositories>
<mongo:mongo id="mongotest" host="${mongo.host}" port="${mongo.port}" write-concern="SAFE">
</mongo:mongo>
<mongo:db-factory dbname="${mongo.dbname}" mongo-ref="mongotest"/>
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
</bean>
<bean id="actorFacade" class="es.mi.casetools.praetor.facade.impl.DefaultActorFacade">
</bean>
</beans>
I also have a little Spring test that fails loading the above application context giving the exception I listed near the top.
I tried adding the following but I get the same exception.
<bean id="actorRepositoryCustomImpl" class="es.mi.casetools.praetor.persistence.springdata.repositories.ActorRepositoryCustomImpl"></bean>
Has someone got a clue of what the error may be?

Miguel's comment solved the problem. I had given the wrong name to the implementing class. I've seen similar questions around so I'll try to clarify the solution in the hope that it helps someone else.
I have the following interface definition
public interface ActorRepository extends MongoRepository<Actor, String>, ActorRepositoryCustom
The custom interface definition looks like this:
public interface ActorRepositoryCustom
So my error was naming the implementation of ActorRepositoryCustom with ActorRepositoryCustomImpl, expecting Springdata would pick up the implementation as its postfix is the default one Impl. The thing is, Springdata looks for ActorRepositoryImpl by default, even though what you are implementing is ActorRepositoryCustom. The solution is using the optional attribute repository-impl-postfix and set it to CustomImpl.

Related

No consumers available on endpoint: Endpoint[direct://LookUpRoute]

I'm new to Apache Camel. I'm trying to send an exchange from a java method to a route but it gives me "Caused by: org.apache.camel.component.direct.DirectConsumerNotAvailableException: No consumers available on endpoint" error. I want to understand what exactly this error is and when do we get this?
#EndpointInject(uri = "direct:reportRoute")
private ProducerTemplate templatereportRoute;
public void saveDataFromExchange(Map<String, Object> DataMap){
List<Map<String, Object>> paramList = new ArrayList<Map<String, Object>>();
List<Map<String, Object>> rows = templatereportRoute.requestBody("direct:reportReport", DataMap, List.class);
<from uri="direct:reportRoute"/>
<log message=" - ${body}" loggingLevel="INFO"/>
<setProperty propertyName="DataMap">
<simple>${body}</simple>
</setProperty>
The error you encounter means that you are sending to a direct endpoint that does not exist in the Camel Context.
Since you posted an XML fragment that defines the route in question there are two possible problems (as already commented by #claus-ibsen):
The XML you posted is not in use. You are starting a Camel Context but it does not use your XML code. Are you using Spring? Then you can define your Camel routes in Spring XML.
Your setup is fine but your Java code sends the message too early, i.e. before the direct endpoint is up and running. You can put this code in a Test class and run it after the Camel context is started and ready.
Try put in public class from routerBuilder implemention the anotation #Component from Spring context
Ex:
#Component //<<<<---- This
public class RouterClass extends RouteBuilder {
#Override
public void configure() throws Exception {
}
}//class closure

Passing parameter to bean's method in camel blueprint

I'm trying to call bean's public method by passing parameter .But i'm unable to run it.Here is my sample blueprint code(I have written from clause but here i'm pasting only necessary code)-
<bean id="ProcessorRef" class="com.healthedge.customer.THC.extractor.ProcessorClass">
<to uri="bean:ProcessorRef" />
Processor class-
public class ProcessorClass{
public String whatAmI(String str) {
return "I am "+str;
}
}
Now in above example how can I invoke whatAmI method with parameter from blueprint?TIA
You can do it by calling directly the method you want
<bean id="ProcessorRef" class="com.healthedge.customer.THC.extractor.ProcessorClass">
<bean ref="ProcessorRef" method="whatAmI('your_parameter_here')" />
If the value you want to pass to whatAmI method is in header, you can do like this.
<to uri="bean:ProcessorRef?method=whatAmI(${header.xyz})" />
If its a constant string, you can put the string directly in place of ${header.xyz}
Another option is to modify your whatAmI method to
public class ProcessorClass{
public String whatAmI(Exchange exchange) {
// exchange has many methods, with which you can access headers and body.
}
}
In such a case you can write the route like this
<to uri="bean:ProcessorRef?method=whatAmI" />
Personally, I would prefer second option, because it gives you access to complete exchange object, which would have all the details.

Issue with Camel custom #Converter using Spring DSL

I Just want to learn custom converter and ran into issue. Any help is much appreciated. Camel Version 2.17 and JBoss Fuse 6.3
#Converter
public class MyConvertor{
public MyConvertor(){}
#Converter
public static String convertTo(Exchange exchange) {}
}
In My Spring DSL
<convertBodyTo charset="UTF-8" id="_convertBodyTo1" type="com.x.convertor.MyConvertor"/>
In META-INF/services/org/apache/camel/TypeConverter
com.x.convertor.MyConvertor
Error message :
org.apache.camel.InvalidPayloadException: No body available of type: com.x.convertor.MyConvertor but has value: GenericFile[output.txt] of type: org.apache.camel.component.file.GenericFile on: output.txt. Caused by: No type converter available to convert from type:
at org.apache.camel.processor.Pipeline.process(Pipeline.java:121)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:83)
Caused by: org.apache.camel.NoTypeConversionAvailableException: No type converter available to convert from type: org.apache.camel.component.file.GenericFile to the required type: com.x.convertor.MyConvertor
There are a couple of errors. The type attribute should be your target type (the type you want after conversion).
<convertBodyTo charset="UTF-8" id="_convertBodyTo1" type="java.lang.String"/>
Camel can do this conversion automatically. If you want to write a converter on your own, mind that converter method should have the expected input type as parameter, and not the Exchange (which can be an optional second parameter from Camel 2.16 onwards).
Class should be something like:
#Converter
public class MyConvertor{
public MyConvertor(){}
#Converter
public static String convertTo(GenericFile body, Exchange exchange) {
// The exchange parameter is optional
}
}
See https://camel.apache.org/type-converter.html
If you want to read the content of a CSV file to transform it into a POJO, use Bindy component.

Camel JAXB marshalling return XML object type?

I am sending a Java object to producer endpoint and waiting for the marshalled XML object. I tried changing it to Node object/ File object but it is giving ClassCastException.
So took the xmlObj in an object class type. What should be the correct class to capture the response?
public class ClientEight {
#Produce(uri = "direct:invoice")
ProducerTemplate template;
public static void main(String args[]) throws InterruptedException {
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("resources/camel-configTen.xml");
InvoiceXml invoice = new InvoiceXml("fdf3443", 3454, 435345.44 f, "hfhfddfdg"); //any java object we are passing
ClientEight client = (ClientEight) ctx.getBean("client");
Object xmlObj = client.template.requestBody(invoice);
System.out.println(xmlObj);
}
}
Above is a client code which you are using to send the Java object to a producer endpoint and since you are using template.requestBody, you are getting back the object returned.
<camel:camelContext>
<camel:dataFormats>
<!-- path to jaxb annotated class -->
<camel:jaxb id="invoiceJaxb" contextPath="com.java.bean"
prettyPrint="true" />
</camel:dataFormats>
<camel:route>
<camel:from uri="direct:invoice" />
<camel:marshal ref="invoiceJaxb" />
<camel:log message=" ${body}" />
<camel:to uri="file://src/resources?fileName=One.xml"/>
</camel:route>
</camel:camelContext>
the unmarshall processor return a stream, not a single object. In camel, more generally, if you want a specific type, you shouldn't get directly a body as an object, but use the various methods to convert the body into that type.
Try :
Document document = client.template.requestBody(invoice, org.w3c.dom.Document.class);

Camel Blueprint Testing - how can I dynamically replace/proxy a remote service referenced in Blueprint in order to prevent use of the real service?

I have the following scenario:
I have an OSGI bundle that has a service reference defined in the blueprint XML that references an interface in a remote bundle, and a bean that uses one of the impl's methods to populate a Properties object.
Relevant snippet from Bundle #1's XML (the consumer):
...
<!-- other bean definitions, namespace stuff, etc -->
<!-- reference to the fetching service -->
<reference id="fetchingService" interface="company.path.to.fetching.bundle.FetchingService" />
<!-- bean to hold the actual Properties object: the getConfigProperties method is one of the overridden interface methods -->
<bean id="fetchedProperties" class="java.util.Properties" factory-ref="fetchingService" factory-method="getProperties" />
<camelContext id="contextThatNeedsProperties" xmlns="http://camel.apache.org/schema/blueprint">
<propertyPlaceholder id="properties" location="ref:fetchedProperties" />
...
<!-- the rest of the context stuff - routes and so on -->
</camelContext>
Remote Bundle's blueprint.xml:
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:camel="http://camel.apache.org/schema/blueprint"
xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">
<cm:property-placeholder id="config-properties" persistent-id="company.path.configfetcher" />
<bean id="fetchingService" class="company.path.to.fetching.bundle.impl.FetchingServiceImpl" scope="singleton" init-method="createLoader" depends-on="config-properties">
<property name="environment" value="${environment}" />
<property name="pathToRestService" value="${restPath}" />
</bean>
<service ref="fetchingService" interface="company.path.to.fetching.bundle.FetchingService" />
<!-- END TESTING -->
</blueprint>
From Impl Class:
public synchronized Properties getProperties() {
if(!IS_RUNNING) {
// timer task that regularly calls the REST api to check for updates
timer.schedule(updateTimerTask, 0, pollInterval);
IS_RUNNING = true;
}
//Map<String, Properties> to return matching object if it's there
if(PROPERTIES_BY_KEY.containsKey(environment)) {
return PROPERTIES_BY_KEY.get(environment);
}
/* if nothing, return an empty Properties object - if this is the case, then whatever bundle is relying on these
* properties is going to fail and we'll see it in the logs
*/
return new Properties();
}
The issue:
I have a test class (extending CamelBlueprintTestSupport) and there are a lot of moving parts such that I can't really change the order of things. Unfortunately, the properties bean method gets called before the CamelContext is started. Not that big a deal because in the test environment there is no config file to read the necessary properties from so the retrieval fails and we get back an empty properties object [note: we're overriding the properties component with fakes since it's not that class being tested], but in a perfect world, I'd like to be able to do two things:
1) replace the service with a new Impl()
2) intercept calls to the getProperties method OR tie the bean to the new service so that the calls return the properties from the fake impl
Thoughts?
Edit #1:
Here's one of the things I'm doing as a workaround right now:
try {
ServiceReference sr = this.getBundleContext().getServiceReference(FetchingService.class);
if(sr != null) {
((FetchingServiceImpl)this.getBundleContext().getService(sr)).setEnvironment(env);
((FetchingServiceImpl)this.getBundleContext().getService(sr)).setPath(path);
}
} catch(Exception e) {
log.error("Error getting Fetching service: {}", e.getMessage());
}
The biggest problem here is that I have to wait until the createCamelContext is called for a BundleContext to exist; therefore, the getProperties call has already happened once. As I said, since in the testing environment no config for the FetchingService class exists to provide the environment and path strings, that first call will fail (resulting in an empty Properties object). The second time around, the code above has set the properties in the impl class and we're off to the races. This is not a question about something that isn't working. Rather, it is about a better, more elegant solution that can be applied in other scenarios.
Oh, and for clarification before anyone asks, the point of this service is so that we don't have to have a .cfg file for every OSGI bundle deployed to our Servicemix instance - this central service will go and fetch the configs that the other bundles need and the only .cfg file that need exist is for the Fetcher.
Other pertinent details:
Camel 2.13.2 - wish it was 2.14 because they've added more property-placeholder tools to that version that would probably make this easier
Servicemix - 5.3.1
Have you tried overriding CamelBlueprintTestSupport's addServicesOnStartup in your test (see "Adding services on startup" http://camel.apache.org/blueprint-testing.html)?
In your case something like:
#Override
protected void addServicesOnStartup(Map<String, KeyValueHolder<Object, Dictionary>> services) {
services.put(FetchingService.class.getName(), asService(new FetchServiceImpl(), null));
}

Resources