Apache Camel - Array of key/pair lines to object - apache-camel

I have a TXT file with user data separated by blank lines
Name : Daniele
City : Genoa
Country : Italy
Name : Giada
City : Milan
Country : Italy
I'm trying to convert that in POJO and eventually in CSV.
My route at the moment is like :
from("file://data/input")
.split(body().tokenize("\n\r\n"))
.to("direct:card");
from("direct:card")
.unmarshal().bindy(BindyType.KeyValue, User.class);
#Message(keyValuePairSeparator = ":", pairSeparator = "\n")
public class User {
#KeyValuePairField(tag = 1)
String name;
#KeyValuePairField(tag = 2)
String city;
#KeyValuePairField(tag = 3)
String country;
.... getter / setter ...
}
But the KeyValue type of bindy expects key to be int. So i can't use it.
What could I use to reach my goal ?

You can use the BindyType.Csv to unmarshall your input file as csv data:
from("direct:card")
.unmarshal().bindy(BindyType.Csv, User.class);
You should then update your target POJO mapping for a #CsvRecord one:
#CsvRecord(separator = ":", crlf = "UNIX")
public class User {
#DataField(pos = 1, trime = true)
String name;
#DataField(pos = 2, trime = true)
String city;
#DataField(pos = 3, trime = true)
String country;
// getter / setter...
}

Related

How to call correctly a String splitting method from another class?

Im trying to access the Spring splitting method from Person class in Main class, but it doesn't show me only the last result from the text. Its working very good when im integrating System.out.prinln in Person class, in method body but In this homework im not aloud to use System.out in Person class, only in Main class. The result must split the text in "Surname , Name , City". Where am i doing wrong? Thank you!
public class Person {
public String surname;
public String name;
public String city;
public Person(String text) {
String[] person = text.split(" ");
for (int i = 0; i < person.length; i++) {
String surname = person[i].split("[.]")[0];
String name = person[i].split("[./]")[1];
String city = person[i].split("/")[1];
this.surname = surname;
this.name = name;
this.city = city;
}
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person("John.Davidson/Berlin Michael.Barton/Rome Ivan.Perkinson/Munich");
System.out.println(p1.surname + p1.name + p1.city);
// the result is the only the last persons info
}
}

Error Room Database: Cannot figure out how to save this field into database. You can consider adding a type converter for it

I have a problem when I want to record into Room database my JSON.
My data class is:
data class CurrentWeatherEntry(
#SerializedName("temperature")//
val temperature: Int,
#SerializedName("weather_code")
val weatherCode: Int,
#SerializedName("weather_icons")
val weatherIcons: List<String>,
)
{
#PrimaryKey(autoGenerate = false)
var id : Int = CURRENT_WEATHER_ID
}
I get error: Cannot figure out how to save this field into database. You can consider adding a type
converter for it.
private final java.util.List<java.lang.String> weatherIcons = null;
How to create converter?
object Converter {
private val gson = Gson()
private val listTypeConverter = object : TypeToken<List<String>>() {}.type
#TypeConverter
#JvmStatic
fun fromListToIcon(list: List<String>): String = gson.toJson(list, listTypeConverter)
#TypeConverter
#JvmStatic
fun fromIconToList(icon: String): List<String> = gson.fromJson(icon, listTypeConverter)
}
Then add #TypeConverters(Converter::class) at the top of your DataBase:
#TypeConverters(Converter::class)
abstract class YourDB : RoomDatabase()

Converting string[] form values to the required types of string and int

I have a HTTP Post action whereby I am posting a HttpPostedFileBase and a FormCollection as my parameters
My controller action is as follows:
[HttpPost]
public ActionResult NewContent(HttpPostedFileBase postedFile,string username, FormCollection form)
{
if (postedFile != null)
{
HttpPostedFileBase postedFileCopy = postedFile;
postedFileCopy.InputStream.Position = 0;
Stream stream = postedFile.InputStream;
//avm.AddContent(postedFile, stream, "jpmcfeely");
string[] name = form.GetValues("name");
string[] author = form.GetValues("author");
string[] description = form.GetValues("description");
DateTime uploaddate = DateTime.Today;//form.GetValues("uploaddate");
DateTime expirydate = DateTime.Today.AddMonths(1);//form.GetValues("expirydate");
string[] participationpoints = form.GetValues("participationpoints");
string[] contenttypeid = form.GetValues("contenttypeid");
try
{
avm.AddContent(postedFile, stream, "jpmcfeely", name.ToString(), author.ToString(), description.ToString(), uploaddate, expirydate, Convert.ToInt32(participationpoints), Convert.ToInt32(contenttypeid));
}
catch (Exception ex)
{
return RedirectToAction("Index", "Admin");
}
}
I then have a method in my ViewModel which adds the details of the form collection to my sql storage table as follows:
public void AddContent(HttpPostedFileBase content, System.IO.Stream stream, string userName, string name, string author, string description, string uploadDate, string expiryDate, int participationPoints, int contentType)
{
string contentUri = "";
Content newContent = new Content();
contentUri = Helpers.ContentUtils.AddContentToBlob(content, stream, "useravatar", content.FileName);
newContent.Name = name;
newContent.Author = author;
newContent.Description = description;
newContent.UploadDate = DateTime.Today;
newContent.ExpiryDate = DateTime.Today.AddMonths(1);
newContent.ParticipationPoints = 50;
newContent.ContentBlobURL = contentUri;
newContent.ContentTypeID = contentType;
this.contentRepository.Add(newContent);
this.contentRepository.SaveChanges();
}
If I build the solution it compiles without error but on save of the content inside the try block on the controller I am getting the following error:
Unable to cast object of type 'System.String[]' to type 'System.IConvertible'
If I just pass the string values in by hardcoding then the method saves as expected so my problem is simply converting these to the appropriate format. What is best approach to do this or am I missing a step?
Change this snippet
Convert.ToInt32(participationpoints), Convert.ToInt32(contenttypeid)
to this
Convert.ToInt32(participationpoints[0]), Convert.ToInt32(contenttypeid[0])

Unexpected Bindy behaviour - camel

When working with bindy, I have create a test that provides invalid CSV input.
When looking at the documentation ( http://camel.apache.org/bindy.html ), it states:
If this field is not present in the record, than an error will be raised by the parser with the following information :
Some fields are missing (optional or mandatory), line :
But when I run my test, the invalid line is simply ignored, no errors are raised. I declare three required fields, so I'd expect an error.... What am I doing wrong?
Barry
Here are some code-snippets to clarify
The route
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
JaxbDataFormat xmlFormat = new JaxbDataFormat();
xmlFormat.setContextPath("be.smals.dp.asktutor.response");
BindyCsvDataFormat csvFormat = new BindyCsvDataFormat ("be.smals.dp.asktutor.response");
context.setTracing(true);
from("direct:marshall")
.wireTap("log:test")
.unmarshal(csvFormat)
.to("mock:marshall");
from("direct:unmarshall")
.marshal(xmlFormat)
.wireTap("log:test")
.to("mock:unmarshall");
}
};
}
Part of my test
#Test
public void testTransformFromCSVToXML() throws Exception {
// Create CSV input and process it
String payload = AskTutorResponseCSVMother.getInvalidCSVLines();
template.sendBody("direct:marshall", payload);
AskTutorsResponse askTutorsResponse =
ExchangeToObjectHelper.getAskTutorsResponseObjectFromExchange(
mockMarshall.getExchanges().get(0));
assertEquals("00000000123", askTutorsResponse.getAskTutorResponses().get(0).getSsinChild());
The input csv string
public static String getInvalidCSVLines () {
String payload = "";
payload += "00000000321;20121212" + NEWLINE;
payload += "10000000123;10000000321;20131010" + NEWLINE;
payload += "20000000123;20000000321;20100909" + NEWLINE;
return payload;
}
And my (straight-forward) bindings:
#XmlType
#XmlAccessorType(XmlAccessType.NONE)
#CsvRecord(separator = ";", skipFirstLine = false)
public class AskTutorResponse {
#DataField(pos = 1, required = true)
#XmlElement(name = "SINNChild", required = true)
private String ssinChild;
#DataField(pos = 2)
#XmlElement(name = "SINNTutor", required = true)
private String ssinTutor;
#DataField(pos = 3)
#XmlElement(name = "date", required = true)
private String date;
I've had problems where multiple classes with bindy annotations in the same package failed to properly unmarshal. The reason is that bindy tried to unmarshall each CSV line into an instance of each annotated class. My first fix was to put each bindy class into its own package. I've since written my own bindy data format that allows a single class to be specified as the unmarshal target. Here is the code.

GWT: creating associated jsarray

I want to create a js array of type
Name(
{title : "Mr.",firstname : "Bill",lastname : "Gates"},
{title : "Mr.",firstname : "Bill",lastname : "Gates"},
{title : "Mr.",firstname : "Bill",lastname : "Gates"}
)
So basically i want to create associated array.
All the examples are like converting javascript array to java but in my case i want the other way round. I will be filling this array from java.
JSArray and JsMixedArray seems to be doing this but i could figure out how to add to them.
One approach could be to use a JSNI method to create the items/entries of your Array/Map as follows:
JsArray arr = JavaScriptObject.createArray().cast();
arr.push(newEntry("Mr.", "Bill", "Gates"));
....
private final native JavaScriptObject newEntry(String title,
String firstname, String lastname)/*-{
return {title: title, firstname: firstname, lastname: lastname};
}-*/;
You could also try to create the data structure you have in mind using the JSON utility methods: Put JSONObjects inside a JSONArray.
Variable $wnd.v will contain an array of objects.
Note: you will need to find a way how to convert your Java objects to a JSON (i used restygwt).
class PersonList {
List<Person> list;
}
class Person {
String title;
String firstName;
String lastName;
public Person () {}
public Person(String title, String firstName, String lastName) {
this.title = title;
this.firstName = firstName;
this.lastName = lastName;
}
}
public class Main implements EntryPoint {
public interface PersonCodec extends JsonEncoderDecoder<PersonList> {
}
PersonCodec personCodec = GWT.create(PersonCodec.class);
public void onModuleLoad() {
List<Person> list = new ArrayList<Person>();
list.add(new Person("Mr.", "Bill", "Gates"));
list.add(new Person("Mr.", "Andrey", "Mormysh"));
PersonList personList = new PersonList();
personList.list = list;
String json = personCodec.encode(personList).toString();
setPersonList(json);
}
public static native void setPersonList(String personListJson)/*-{
$wnd.v = eval("(" + personListJson + ")").list;
alert($wnd.v[0].firstName); // Output: 'Bill'
}-*/;
}
You can create empty JavaScriptObject from Java but you cannot populate them from there, so use the dark side of the force:
private native JavaScriptObject putString(JavaScriptObject jso, String key, String value)/*-{
jso[key] = value;
return jso;
}-*/;
private native JavaScriptObject putObject(JavaScriptObject jso, String key, JavaScriptObject value)/*-{
jso[key] = value;
return jso;
}-*/;
void someJavaFunction() {
JavaScriptObject fromJava = JavaScriptObject.createObject();
fromJava = putString(fromJava, "foo", "bar");
fromJava = putObject(fromJava, "baz", fromJava);
}

Resources