Rest DSL path typing to a POJO, can I register the POJO as a Bean and call the id to reference it? - spring-boot

This is a very low impact "issue" and I'm just looking out to learn something new about Camel and how it works.
I'm working to build a springboot service using camel context routes, and while it's working fine (so far), I'd like to set the rest path type to a class without having to explicitly call the package location, and instead, reference the class as a bean and use it's id to call it.
I have defined a camelContext, I have the rest, restConfigurations and the necessary http methods (get, post, put...), here's a mock of what I have right now.
I've registered a ServiceImpl class as a bean and have given it the id Service. In the Route, I can call the bean using a ref to it's id, and select the method that I want.
<beans xmlns ...>
...
<!-- start services -->
<bean class="com.daniel.rest-project.services.ServiceImpl" id="Service"/>
<!-- end services -->
...
<camelContext id="context" xmlns="http://camel.apache.org/schema/spring">
<rest bindingMode="au <!-- <to id="to-7b30ace2-b26d-4301-8bb0-ef007d566ab3" uri="direct:501"/> -->to" enableCORS="true" id="rest">
...
<post consumes="application/json" id="newTask" produces="application/json" uri="/task" type="com.daniel.rest-project.vo.TaskVO">
<description>New Task Object</description>
<param description="Task Object Body." name="body" required="true" type="body"/>
<to uri="direct:newTask"/>
</post>
...
</rest>
...
<route id="route-task-new">
<from id="from-task-new" uri="
<bean id="to-task-new" method="newTask" ref="Service"/>
</route>
...
</camelContext>
</beans>
Now, I've actually got implemented around 150 routes (project is pretty big) and I'm tired of having to declare the rest post type, right now it's using something not really similar to com.daniel.rest-project.vo..
There's a ton of classes that are named similarly and due to internal reasons, best practices are scarce, naming conventions are weird, there's more than one package I need to go to, etc.
It would feel a lot more organized to just define all the objects I need at the start of the XML file and reference them as I go, instead of having to state the whole way there every time, so, is there a way I can define those classes at the start, just like the services, and tell the post rest path to use the id of the bean, instead of having to give it the whole class location? There must be a way and I'm sure I've just been blind enough not to see it in the documentation for the past weeks.
Here's one of the methods I've tried thus far:
<!-- start classes -->
<bean class="com.daniel.rest-project.vo.TaskVO" id="TaskVO"/>
<!-- end classes -->
and then, tell the path to do something like this
<post consumes="application/json" id="newTask" produces="application/json" uri="/task" type="TaskVO">
<description>New Task Object</description>
<param description="Task Object Body." name="body" required="true" type="body"/>
<to uri="direct:newTask"/>
</post>
Which resulted in the following error:
Caused by: org.apache.camel.FailedToCreateRouteException: Failed to create route newTask: Route(newTask)[[From[rest:post:/task?routeId=newTask&... because of java.lang.ClassNotFoundException: TaskVO
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:209)
at org.apache.camel.impl.DefaultCamelContext.startRoute(DefaultCamelContext.java:1143)
..........
Caused by: org.apache.camel.RuntimeCamelException: java.lang.ClassNotFoundException: TaskvO
at org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException(ObjectHelper.java:1830)
at org.apache.camel.impl.DefaultRouteContext.commit(DefaultRouteContext.java:206)
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:1307)
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:204)
TaskVO implements Serializable, and only has one, empty, public constructor, followed by all of it's getters and setters.

Related

Spring Core - Alias and Ids

I started learning Spring today and came across a strange behavior, so seeking any expert help on the behavior. I defined a bean with an id and verified the bean is available via ApplicationContext and Bean factory. Later created more beans with different IDs but created one alias with the exact same Id of the First Bean (xml snippet below)
<!-- Beans -->
<bean id="wolf" class="com.badwolf.spring.SpringWolf">
<constructor-arg type="java.lang.String" value="wolfy" />
<constructor-arg index="1" value="20" />
</bean>
<bean id="sweetWolf" class="com.badwolf.spring.SweetWolf" />
<!-- Aliases -->
<alias name="sweetWolf" alias="wolf" />
Now in the implementation class when getting the bean using "wolf" then getting the bean associated with the "Alias". Is this intended behavior of Spring? Do Aliases take precedence over the bean definition (which seems to be the core of Spring)?
What if my project is split into teams and on integration someone has used the same id and alias and all of a sudden a portion of functionality stops working.
Firstly, there are three Spring bean terminology here, name, alias, and id.
Spring bean can have multiple names, aliases, while it can only have one unique id.
Below is reference from Spring doc
Every bean has one or more identifiers. These identifiers must be unique within the container that hosts the bean. A bean usually has only one identifier, but if it requires more than one, the extra ones can be considered aliases.
So in your case, bean with id of "wolf" has Spring-generated name ("springwolf"), while bean with id "sweetWolf" has two names, Spring-generated name("sweestWolf") and name alias("wolf") (spring-bean-names).
Related discussions for alias vs name (1, 2)
Related discussion for alias vs id (1)

Mule invoke message processor

I came across "invoke" element (link) that can be used to invoke java methods from inside the flow. It seemed a perfect solutions for me, since I don't want to use Callable and entry points resolvers and I want to pass extra parameter to the method.
<invoke object-ref="yourBean"
method="yourMethod"
methodArguments="#[message.inboundProperties['inboundPropertyName']]" />
<set-property propertyName="outboundPropertyName"
value="#[payload]" />
I did something like the code above. My question is: how should I create "yourBean"?
I tried to create:
<spring:bean name="yourBean" class="class"/>
but got:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'yourBean' is defined
I also have other beans defined in my tag, but others seemed to work. Does anyone have similar issue?
EDIT:
When I deleted other beans definitions besides "yourBean" everything started to work, but when I add more beans definitions I got following error when I tried to use "yourBean":
Exception stack is:
1. null (java.lang.NullPointerException)
org.mule.processor.InvokerMessageProcessor:280 (null)
2. null (java.lang.NullPointerException). Message payload is of type: String (org.mule.api.MessagingException)
org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor:35 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/MessagingException.ht
ml)
--------------------------------------------------------------------------------
Root Exception stack trace:
java.lang.NullPointerException
at org.mule.processor.InvokerMessageProcessor.transformArgument(InvokerMessageProcessor.java:280)
at org.mule.processor.InvokerMessageProcessor.evaluateArguments(InvokerMessageProcessor.java:200)
at org.mule.processor.InvokerMessageProcessor.process(InvokerMessageProcessor.java:164)
+ 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
********************************************************************************
Which for me seems like the "yourBean" is not instantiated. But why?
My bean definitions:
<bean id="yourBean" class="com.example.BpmService"/>
<bean id="StatusUpdateContext" class="javax.xml.bind.JAXBContext" factory-method="newInstance">
<constructor-arg>
<array>
<value type="java.lang.Class">
com.example.OrderStatusUpdate
</value>
</array>
</constructor-arg>
</bean>
EDIT: Ok, id/name both some to work for Mule invoke. I have had no problems using invoke with multiple bean definitions. This sounds more like an issue with your beans, which you are not sharing, and/or Spring than Mule invoke.

c3p0 useScatteredAquireTask Spring Bean

Hello I wan't to know how can I set up a bean so that it sets the ScatteredAquireTask to "True".
I've been trying:
<bean id="c3p0Props" class="com.mchange.v2.resourcepool.BasicResourcePool.ScatteredAcquireTask" >
<property name="USE_SCATTTERED_ACQUIRE_TASK" value="true" />
</bean>
I also tried ...resourcepool.experimental.useScatteredAcquireTask... didn't worked. I'm not sure how can I set this on spring. I'm using 0.9.1.2, can't go to 0.9.2.prep1 at the moment. Thanks.
That's because USE_SCATTTERED_ACQUIRE_TASK isn't a property of the ScatteredAcquireTask class (i.e. there's no method called setUSE_SCATTTERED_ACQUIRE_TASK), it's an internal static field of the class that's not accessible to Spring.
You're not going to be able to set that values in a Spring bean defintion, you need to find out how to influence that value by some other means.

looking up beans from resources.xml into controller/service in groovy

I am using groovy-grails with jasper reports to develop an app. I need to lookup 'report bean' based on its parameter (like reportname /id retrived from database, which I will get from customer click) - which will be stored as a property of report bean from resources.xml into either the reportcontroller or reportservice. Also I have to 'get' the jrxml template related to this id and the parameter Map, both defined as properties in the bean. I need to know like how can we achieve this and do we need to define any 'managing beans' in the xml which manage these report beans.
So for example the report bean will look like as follows:
<bean id="DeptReport" class="com.myapp.reporting.domain.Report">
<property name="reportName" value="Dept Report"/>
<property name="reportFiles">
<map>
<entry key="JasperPrint" value="DeptRoles.jrxml"/>
</map>
</property>
<property name="promptforparameter" value="true"/>
<property name="parameter" value="department_id"/>
<property name="displayName" value="report.deptReport.name"/>
</bean>
There will be many beans like this.
Also the .jrxml file for all reports are stored in a directory and I want to wire that location into the reporting context so that whenever a report is clicked on the front end I want to look up these values from the context into the report service/controller to generate the report. I know we have to do like a ctx.getbean(reportId) somewhere but I also want to know how to setup a manager bean with some other properties like template location, datasource, parameter map, reportid and a jasperreportrenderrer object. So this ReportManager bean is loaded reused every time there is a call for another report and persisted across a user session ideally.
You should be able to do something like this:
import org.springframework.context.*
class MyService implements ApplicationContextAware {
ApplicationContext applicationContext
def getBeanByName( String name ) {
applicationContext.getBean( name )
}
}
That's in a grails Service class, but the same should hold true for a controller

Spring RegisterSingleton

I have a following object:
public class TestObject
{
public String Something { get; set; }
}
and a following objects file:
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd">
<object id="TestObject" type="SpringTest.TestObject" autowire="byName"/>
</objects>
What I would like to do is to register singleton and get the TestObject. I am doing this like so:
IConfigurableApplicationContext context = new XmlApplicationContext("objects.xml");
context.ObjectFactory.RegisterSingleton("Something", "something to test");
object obj = context.GetObject("TestObject");
But the objects property Something is always null. I think that this should work or am I doing something wrong?
Many thanks!
I'm not sure what the problem statement is exactly (never used Spring for .NET). But if you want what Don Kirkby suggest you should lookup TargetSources in the reference documentation (assuming that the .NET implementation has them, too).
I think your Something property is not getting set because singletons are instantiated when the application context is instantiated. When you call RegisterSingleton, the TestObject has already been created. The bean wiring is only done when a bean is created.
You might be able to work around this problem by making the singleton instantiate lazily. That way it isn't instantiated until the first time it's requested. Hopefully, that's after you've registered the other singletons it needs.
I don't know exactly what you're trying to accomplish, but if I wanted to change the wiring between some singleton beans at run time without making the beans aware of it, I would introduce some wrapper objects. Each wrapper would implement an interface and then just delegate all methods to its current target bean. To change the wiring, you just change the wrapper's target.
Update: as yawn suggested, Spring.NET has hot-swappable target sources that let you swap out the implementation of a bean at run time. Here's some sample code from the documentation that shows how to swap the bean implementation:
HotSwappableTargetSource swapper =
(HotSwappableTargetSource) objectFactory.GetObject("swapper");
object oldTarget = swapper.swap(newTarget);
The XML definitions in the documentation look like this:
<object id="initialTarget" type="MyCompany.OldTarget, MyCompany">
</object>
<object id="swapper"
type="Spring.Aop.Target.HotSwappableTargetSource, Spring.Aop">
<constructor-arg><ref local="initialTarget"/></constructor-arg>
</object>
<object id="swappable"
type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
<property name="targetSource">
<ref local="swapper"/>
</property>
</object>
Why aren't you using scope="singleton" if you want a singleton or am I missing something?

Resources