Camel Velocity Template - access java object properties - apache-camel

I have a camel route which uses Velocity template and in the body I have an object defined as following:
class MailImpl extends AbstractMail{
private BodyContext bodyContext;
public BodyContext getBodyContext() {
return bodyContext;
}
public void setBodyContext(BodyContext bodyContext) {
this.bodyContext = bodyContext;
}
private String test;
public String getTest() {
return test;
}
public void setTest(String test) {
this.test = test;
}
#Override
public String toString() {
return "MailImpl{" +
"bodyContext=" + bodyContext +
'}';
}
}
class BodyContext{
private String value;
public BodyContext(String value) {
this.value = value;
}
public BodyContext() {
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#Override
public String toString() {
return "BodyContext{" +
"value='" + value + '\'' +
'}';
}
In the velocity template I would like to access the MailImpl object properties, for example I use ${body.test} and ${body.bodyContext.value} but velocity template does not transform those values (it returns as string ${body.test} and ${body.bodyContext.value}).
One solution could be creating headers for each of of the value I need to use in the template, but as my route is dynamic (I select velocity template based on header) I would like to access the body properties in the velocity context. Is this somehow possible?

You can setup a custom Velocity Context by setting the message header "CamelVelocityContext" (since Camel v2.14). From Camel's test case:
Map<String, Object> variableMap = new HashMap<String, Object>();
Map<String, Object> headersMap = new HashMap<String, Object>();
headersMap.put("name", "Willem");
variableMap.put("headers", headersMap);
variableMap.put("body", "Monday");
variableMap.put("exchange", exchange);
VelocityContext velocityContext = new VelocityContext(variableMap);
exchange.getIn().setHeader(VelocityConstants.VELOCITY_CONTEXT, velocityContext);
exchange.setProperty("item", "7");
With following template:
Dear ${headers.name}. You ordered item ${exchange.properties.item} on ${body}.
You get:
Dear Willem. You ordered item 7 on Monday.

Related

Cant access nested list in Json response

Im trying to access some list items from a json response using retrofit but cant seem to be able to access using get method. The ListQuotes seems to be saying null
#JsonPropertyOrder({
"page",
"last_page",
"quotes"
})
public class ListQuoteResponse {
#JsonProperty("quotes")
private List<Quote> quotes = null;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
/**
* No args constructor for use in serialization
*
*/
public ListQuoteResponse() {
}
#JsonProperty("quotes")
public List<Quote> getQuotes() {
return quotes;
}
#JsonProperty("quotes")
public void setQuotes(List<Quote> quotes) {
this.quotes = quotes;
}
#JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
#JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
But when I open the Quote class I am unable to access any of the properties
public class Quote {
#JsonProperty("id")
private Integer id;
#JsonProperty("dialogue")
private Boolean dialogue;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
/**
* No args constructor for use in serialization
*
*/
public Quote() {
}
#JsonProperty("id")
public Integer getId() {
return id;
}
#JsonProperty("id")
public void setId(Integer id) {
this.id = id;
}
#JsonProperty("dialogue")
public Boolean getDialogue() {
return dialogue;
}
#JsonProperty("dialogue")
public void setDialogue(Boolean dialogue) {
this.dialogue = dialogue;
}
I tried using
listQuoteBodyResponse.body().getQuotes() but that only returned random numbers and when I tried using the Quote class for the response directly like
QuoteResponse.body.getDialogue() its just returning null

SpringBoot : RestAPI Returning JSON Array But I want value with label to set in AngularJS

Requirement:
Trying to populate all UNIQUE record in Angular Drop Down List
I am using predefined Table have already data.
REST API URL => http://localhost:8080/getAllCategory
Facing Problem:
API is giving the reponse in JSON Array like [xxx,yyyy,zzzz]. So I am thinking if I can convert JSON Array with some label value which can solve my problem.
Either any other way to get over with this issue.
Note :
If I am not using the native query and using the below code then I am getting all the table value in JSON with label and populating all the record in drop down but I want only UNIQUE
#Repository
public interface CategoryRepository extends JpaRepository<ccCategory,Integer>
{}
My Implementation :
Model :
#Table(name = "cccategory")
public class ccCategory
{
#Id
#Column(name = "[catid]")
public Integer catID;
#Column(name = "[categoryname]")
public String categoryName;
#Column(name = "[active]")
public int active;
public ccCategory() {
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
public int getActive() {
return active;
}
public void setActive(int active) {
this.active = active;
}
}
Repository:
#Repository
public interface CategoryRepository extends JpaRepository<ccCategory,Integer>
{
public static final String FIND_CATEGORYNAME = "SELECT DISTINCT catID,categoryName from ccCategory";
#Query(value = FIND_CATEGORYNAME, nativeQuery = true)
List<ccCategory> getByactive(int active);
}
Controller :
#GetMapping("/getAllCategory")
public List<Object> getAllCategory() {
// public List<ccCategory> getAllCategory() {
System.out.println("***** Call : API getAllCategory() ******");
List<Object> cCategory = categoryRepository.getCategoryName();
return categoryData;
}

Passing a list or array to RESTeasy using get

I've seen this kind of thing described in various examples showing how to create a REST service which takes arrays or a list of objects as part of the URL.
My question is, how to implement this using RESTeasy?
Something like the following would be how i would assume this to work.
#GET
#Path("/stuff/")
#Produces("application/json")
public StuffResponse getStuffByThings(
#QueryParam("things") List<Thing> things);
Create a StringConverter and a use a wrapper object. Here is a quick and dirty example:
public class QueryParamAsListTest {
public static class Thing {
String value;
Thing(String value){ this.value = value; }
}
public static class ManyThings {
List<Thing> things = new ArrayList<Thing>();
ManyThings(String values){
for(String value : values.split(",")){
things.add(new Thing(value));
}
}
}
static class Converter implements StringConverter<ManyThings> {
public ManyThings fromString(String str) {
return new ManyThings(str);
}
public String toString(ManyThings value) {
//TODO: implement
return value.toString();
}
}
#Path("/")
public static class Service {
#GET
#Path("/stuff/")
public int getStuffByThings(
#QueryParam("things") ManyThings things){
return things.things.size();
}
}
#Test
public void test() throws Exception {
Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
dispatcher.getProviderFactory().addStringConverter(new Converter());
dispatcher.getRegistry().addSingletonResource(new Service());
MockHttpRequest request = MockHttpRequest.get("/stuff?things=a,b,c");
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
Assert.assertEquals("3", response.getContentAsString());
}
}
I think you can also use a StringParamUnmarshaller
I had some luck with this, using Collection rather than List. I was unable to make a StringConverter for List work.
#Provider
public class CollectionConverter implements StringConverter<Collection<String>> {
public Collection<String> fromString(String string) {
if (string == null) {
return Collections.emptyList();
}
return Arrays.asList(string.split(","));
}
public String toString(Collection<String> values) {
final StringBuilder sb = new StringBuilder();
boolean first = true;
for (String value : values) {
if (first) {
first = false;
} else {
sb.append(",");
}
sb.append(value);
}
return sb.toString();
}
}
I did the toString from my head. Be sure to write unit tests for it to verify. But of course, everything is easier and clearer when you use Guava. Can use Joiner and Splitter. Really handy.
Just use a wrapper on its own, no need for anything else.
In your endpoint
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
#Path("/find")
#GET
MyResponse find(#QueryParam("ids") Wrapper ids);
And you wrapper looks like this :
public class Wrapper implements Serializable {
private List<BigInteger> ids = Collections.emptyList();
public String toString() {
return Joiner.on(",")
.join(ids);
}
public List<BigInteger> get() {
return ids;
}
public Wrapper(String s) {
if (s == null) {
ids = Collections.emptyList();
}
Iterable<String> splitted = Splitter.on(',')
.split(s);
Iterable<BigInteger> ids = Iterables.transform(splitted, Functionz.stringToBigInteger);
this.ids = Lists.newArrayList(ids);
}
public Wrapper(List<BigInteger> ids) {
this.ids = ids;
}
}

Why can't I add attributes when serializing ObservableCollection<T>?

I'm trying to extend an ObservableCollection with a few custom properties and have it serialize. However, I can't seem to get it to serialize these properties. I'm using .NET 4.0 where they fixed the serialization issues of ObservableCollection, but am still having problems. My hunch is that GetObjectData is being called on the base class and not mine. Any ideas?
[Serializable]
[XmlRoot(ElementName = "MyCollection")]
public class MyCollection : ObservableCollection<MyItem>, ISerializable
{
private string name;
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Name", Name);
}
private MyCollection()
{
Name = string.Empty;
}
public MyCollection(string name)
{
Name = name;
}
public MyCollection(SerializationInfo info, StreamingContext context)
{
Name = (string)info.GetValue("Name", typeof(string));
}
[XmlAttribute]
public string Name
{
get { return name; }
protected set
{
string originalName = name;
name = value;
if (originalName != name)
OnPropertyChanged(new PropertyChangedEventArgs("Name"));
}
}
public void SaveToFile(string path)
{
string directory = Path.GetDirectoryName(path);
if (!Directory.Exists(directory))
Directory.CreateDirectory(directory);
XmlSerializer serializer = new XmlSerializer(typeof(MyCollection));
using (TextWriter textWriter = new StreamWriter(path))
{
serializer.Serialize(textWriter, this);
textWriter.Close();
}
}
public static MyCollection LoadFromFile(string path)
{
XmlSerializer deserializer = new XmlSerializer(typeof(MyCollection));
using (TextReader textReader = new StreamReader(path))
{
MyCollection myCollection = (MyCollection)deserializer.Deserialize(textReader);
textReader.Close();
return myCollection;
}
}
}
XML Serialization does not support this scenario. You simply cannot add anything to a class implementing ICollection.
If you require this, then you will have to implement IXmlSerializable and do the work yourself.
Note that you may be confusing XML Serialization with runtime serialization. XML Serialization doesn't care about the [Serializable] attribute or GetObjectData, etc.

property names are different from original Object in the silverlight

Following is part of service layer which is provided by WCF service :
[Serializable]
public class WaitInfo
{
private string roomName;
private string pName;
private string tagNo;
public string RoomName
{ get { return roomName; } set { this.roomName = value; } }
public string PName
{ get { return pName; } set { this.pName = value; } }
public string TagNo
{ get { return tagNo; } set { this.tagNo = value; } }
}
public class Service1 : IService1
{
public List<WaitInfo> GetWaitingList()
{
MyDBDataContext db = new MyDBDataContext();
var query = from w in db.WAIT_INFOs
select new WaitInfo
{
TagNo = w.PATIENT_INFO.TAG_NO,
RoomName= w.ROOM_INFO.ROOM_NAME,
PName= w.PATIENT_INFO.P_NAME
};
List<WaitInfo> result = query.ToList();
return result;
}
And following is codebehind part of UI layer which is provided by Silverlight
public MainPage()
{
InitializeComponent();
Service1Client s = new Service1Client();
s.GetWaitingListCompleted +=
new EventHandler<GetWaitingListByCompletedEventArgs>( s_GetWaitingListCompleted);
s.GetWaitingListAsync();
}
void s_GetWaitingListCompleted(object sender,
RadControlsSilverlightApplication1.ServiceReference2.GetWaitingListByCompletedEventArgs e)
{
GridDataGrid.ItemsSource = e.Result;
}
And following is xaml code in Silverlight page
<Grid x:Name="LayoutRoot">
<data:DataGrid x:Name="GridDataGrid"></data:DataGrid>
</Grid>
It is very simple code, however what I am thinking weird is property name of object at "e.Result" in the code behind page.
In the service layer, although properties' names are surely "RoomName, PName, TagNo", in the silverlight properties' names are "roomName, pName, tagNo" which are private variable name of the WaitingList Object.
Did I something wrong?
Thanks in advance.
Unless you specifically decorate your class with the DataContract attribute (which you should, instead of Serializable) then a default DataContract will be inferred. For normal Serializable types, this means the fields will be serialized as opposed to the properties.
You can markup your class in either of the following two ways. The latter will use the property accessors when serializing/deserializing your object which may be very useful or be a hassle depending on your circumstances.
[DataContract]
public class WaitInfo
{
[DataMember(Name="RoomName")]
private string roomName;
[DataMember(Name="PName")]
private string pName;
[DataMember(Name="TagNo")]
private string tagNo;
public string RoomName
{ get { return roomName; } set { this.roomName = value; } }
public string PName
{ get { return pName; } set { this.pName = value; } }
public string TagNo
{ get { return tagNo; } set { this.tagNo = value; } }
}
The method I prefer:
[DataContract]
public class WaitInfo
{
private string roomName;
private string pName;
private string tagNo;
[DataMember]
public string RoomName
{ get { return roomName; } set { this.roomName = value; } }
[DataMember]
public string PName
{ get { return pName; } set { this.pName = value; } }
[DataMember]
public string TagNo
{ get { return tagNo; } set { this.tagNo = value; } }
}

Resources