I am getting the following error while push/add items to an array in groovy.
$groovy main.groovy
Caught: groovy.lang.MissingMethodException: No signature of method: [LProgressNotes;.push() is applicable for argument types: (ProgressNotes) values: [ProgressNotes#d35dea7]
Possible solutions: sum(), plus(java.util.Collection), plus([Ljava.lang.Object;), plus(java.lang.Object), use([Ljava.lang.Object;), plus(java.lang.Iterable)
groovy.lang.MissingMethodException: No signature of method: [LProgressNotes;.push() is applicable for argument types: (ProgressNotes) values: [ProgressNotes#d35dea7]
Possible solutions: sum(), plus(java.util.Collection), plus([Ljava.lang.Object;), plus(java.lang.Object), use([Ljava.lang.Object;), plus(java.lang.Iterable)
at main$_buildOutNotes_closure2.doCall(main.groovy:82)
at main.buildOutNotes(main.groovy:75)
at main$buildOutNotes.callCurrent(Unknown Source)
at main.run(main.groovy:64)
Here is the function:
def buildOutNotes(incomingNotes, systemNotes) {
ProgressNotes[] outNotes = systemNotes;
//iterate incoming chares
incomingNotes.each { incoming ->
//split the note further
def iNote = splitIncoming(incoming);
//check that the incoming note is in the system note
def foundNotes = systemNotes.findAll { it.ProgressNote == iNote.ProgressNote }
if(!foundNotes){
//add the incoming note to the outNote
outNotes.push(iNote);
}
}
return outNotes;
}
Here are the articles that show push and add use
https://mrhaki.blogspot.com/2015/01/groovy-goodness-pop-and-push-items-in.html
def list = ['Groovy', 'is', 'great!']
list.push('rocks!')
http://docs.groovy-lang.org/next/html/documentation/working-with-collections.html
def list = [5, 6, 7, 8]
emptyList.add(5)
I am building the example code on https://www.tutorialspoint.com/execute_groovy_online.php.
You can view the example here
http://tpcg.io/NGw4szCv
Here is the full code as well:
//package com.javacodegeeks.groovy.date;
//import static java.util.Calendar.*;
//import groovy.json.*;
//import java.util.Properties;
//import java.util.List;
//progress notes object
class ProgressNotes {
def ActionDate
String ActionBy
String Status
String ProgressNote
ProgressNotes(inActionDate, inActionBy, inStatus, inNote){
this.ActionDate = inActionDate
this.ActionBy = inActionBy
this.Status = inStatus
this.ProgressNote = inNote
}
}
//delimiter
String delimiter = "##";
//out notes
ProgressNotes[] outNotes;
//date patterns
def dateInSystemPattern = "yyyy-MM-dd HH:mm:ss";
def dateIncomingPattern = "MM/dd/yyyy hh:mm ";
/************** SAMPLE DATA START ****************/
//incoming note string
String incomingNote = "2019-12-15T01:29:44 User1: December 13 went to pickup the toilet at the wholesaler " +
"then went to site then remove and replace the toilet then found out that there is a " +
"fruit inside the toilet then clean up the site and silicone around the toilet then " +
"throw the old toilet at dumpster." + delimiter +
"2019-12-13T10:43:05 User2: applied 3 bottles of urinal treatment. let sit for an " +
"hour. augered out urinal main. draining excellent. tried augering toilet. object stuck in " +
"toilet. will not come out. Don will replace." + delimiter +
"2019-12-13T09:18:51 user3: PO 508758 - unclog Washroom " +
"Details: " +
"Unclog toilet bowl and urinal in. Room 116.";
//in system notes
ProgressNotes[] systemNotes = [
["2012-01-26T14:52:50", "User1", "DISPATCHED", "reassign to Space Planning to confirm space availability"],
["2012-02-01T12:23:05", "User2", "DISPATCHED", "spoke to requestor and she has a few relocations and POD requirements."],
["2012-02-01T12:23:45", "User3", "DISPATCHED", "Contacted Customer for clarification spreadsheet is forthcoming for this request."],
["2012-02-03T18:45:00", "User1", "DISPATCHED", "Extending date to allow for clean-up of backlog."]
];
/************** SPLIT incomingNote ****************/
def incomingNotes = [];
if (incomingNote != ""){
incomingNotes = incomingNote.split(delimiter);
}
/************** PICK NOTES ****************/
if (!incomingNotes){
//No incoming notes push the system notes out
outNotes = systemNotes;
}
else{
//check and build the outnotes
outNotes = buildOutNotes(incomingNotes, systemNotes);
}
println("OUTNOTES Length: " + outNotes.length)
println(" ");
/************** HELPER METHODS ****************/
def buildOutNotes(incomingNotes, systemNotes) {
ProgressNotes[] outNotes = systemNotes;
//iterate incoming chares
incomingNotes.each { incoming ->
//split the note further
def iNote = splitIncoming(incoming);
//check that the incoming note is in the system note
def foundNotes = systemNotes.findAll { it.ProgressNote == iNote.ProgressNote }
if(!foundNotes){
//add the incoming note to the outNote
outNotes.push(iNote);
}
}
return outNotes;
}
def splitIncoming(incoming){
//date time characters
int dateTimeChars = 20;
def dateAndTimePart = incoming.substring(0,dateTimeChars).trim();
String remainingNote = incoming.substring(dateTimeChars);
String userPart = "";
String notePart = "";
def remainingNotes = remainingNote.split(":");
if(remainingNotes){
userPart = remainingNotes.getAt(0);
notePart = incoming.substring(dateTimeChars+userPart.length()+1).trim();
}
//build the object
def outNote = new ProgressNotes(dateAndTimePart, userPart, "", notePart);
return outNote;
}
You use an array in your code (ProgressNotes[]), not a list (List<ProgressNotes>). Any of the mentioned methods (add and push) does not exist for Java (and thus Groovy) arrays. An array is fixed size, so once initialized, you can't add any new elements to it - you can only replace existing elements. If you try to add a new element to the array, you will get IndexOutOfBoundsException. Just look at this simple example:
String[] list = ["foo", "bar"]
assert list[0] == "foo"
assert list[1] == "bar"
try {
list[2] = "new"
} catch (IndexOutOfBoundsException e) {
println "Caught!"
}
list[1] = "abc"
println list
Output:
Caught!
[foo, abc]
If you want to use List.add() or List.push() (or event groovier leftShift like [] << "elem") you need to use a list instead of an array. Arrays are a good choice if you know the size of the collection is fixed.
//out notes
List<ProgressNotes> outNotes;
I have a combo box its values are 10, 20, 30, 40, 50 when I create a document and display it in a view the number is appeared but I want to display its labels (labels are text) not numbers.
Can someone please help me find out how to solve this issue.
Thanks
I tend to add values of a given checkbox into a Resource Bundle, and then access that Resource Bundle both from the xp:selectItems and the xp:viewColumn values.
First, I'll create a Resource Bundle which I set as "label", with the following values:
itemsList_status=Draft|0,Published|1,Archived|-1
itemsList_delimiter=,
Here's an example of the xp:selectItems for an xp:combobox:
<xp:selectItems>
<xp:this.value>
<![CDATA[#{javascript:return getSelectItems('status');}]
</xp:this.value>
</xp:selectItems>
Here's my getSelectItems() SSJS function:
var getSelectItems : function(key) {
try {
var returnObj = new Array();
var items = null;
switch(key) {
case "status" :
items = #Text(label.itemsList_status).split(label.itemsList_delimiter);
break
}
for( var n=0, l=items.length; n < l; n++) {
returnObj.push(items[n]);
}
return returnObj;
} catch(e) {
print(database.getTitle() + " SSJS Error for getSelectItems()");
print(e.toString());
}
}
Run this function, and it'll return 3 options that read Draft, Published, and Archived while actually storing 0, 1, and -1 respectively. The problem that you're running into - and what using this abstracted method of storing your labels:values in a Resource Bundle + SSJS to address - is when you go to read the value but actually want to display the label...
Here's my getSelectedValue() function:
var getSelectedValue : function(key, thisValue) {
try {
var returnObj = new Array();
var items = null;
switch(key) {
case "status" :
items = #Text(label.itemsList_status).split(label.itemsList_delimiter);
break
}
var s = "";
var l = "";
for( var n=0, i=items.length; n < i; n++) {
if(items[n].indexOf("|") == -1) {
s = items[n];
l = items[n];
} else {
s = items[n].split("|").pop();
l = items[n].split("|").shift();
}
if(thisValue == s) {
return l;
}
}
return thisValue;
} catch(e) {
print(database.getTitle() + " SSJS Error for getSelectedValue()");
print(e.toString());
}
}
Now you'd pass the current value and the desired label:value Resource Bundle item handle, and this function spits out the correlating label. Here is how I use it in an xp:viewColumn:
<xp:viewColumn
id="viewColumn_status">
<xp:this.value><![CDATA[#{javascript:return ""}]]></xp:this.value>
<xp:text
value="#{javascript: return
getSelectedValue('status',thisEntry.getDocument().getItemValueString('status'))}" />
<xp:viewColumnHeader
value="#{label.viewColumnHeader_posts_status}"
id="viewColumnHeader_status">
</xp:viewColumnHeader>
</xp:viewColumn>
... and that's about it - the Resource Bundle entry to "itemList_status" acts as the authoritative master for the label:value pairs, so you just check that for the input building and deconstruct it for the labeling of stored values.
Hope this helps!
Using aliases is analog to the usage in a normal form.
Use a formula item for the values:
return ["- Please select -|", "ten|10", "twenty|20", "thirty|30"];
But keep in mind that the values that is stored is always TEXT and not a number.
I'm trying to pass multiple list types as a parameter using the same method variable and then loop through the types based on which type as been past. I tried using a generic method but it's not working. Below are pseudo/example codes. The List SAS_F_DISAGG_F and List SAS_C_DISAGG_C are SQL/Entity, and the List DisaggReportGroups is a class object. I'm trying to pass the entity lists.
protected void GetReportGroup()
{
DisaggReportGroups rptGroup = new DisaggReportGroups();
List<DisaggReportGroups> disagreportGroup = new List<DisaggReportGroups>();
disagreportGroup.Add(rptGroup);
DisaggregatedReportData disagReportData = new DisaggregatedReportData();
foreach (var reportGroup in disagreportGroup)
{
if (reportGroup.FuturesOnly == "Futures Only, " & reportGroup.Agriculture == "Agriculture")
{
List<SAS_F_DISAGG_F> futONlyDisagReportData = disagReportData.GetFuturesOnlyReportData(reportGroup.Agriculture).ToList();
CreateLongFormatReport<List<SAS_F_DISAGG_F>>(reportGroup.AgricultureFilenameFOLF, reportGroup.FuturesOnly, reportGroup.Agriculture, futONlyDisagReportData);
}
else if (reportGroup.FOCombined == "Futures and Options Combined, " & reportGroup.Agriculture == "Agriculture")
{
List<SAS_C_DISAGG_C> combinedDisagReportData = disagReportData.GetFOCombinedReportData(reportGroup.Agriculture).ToList();
CreateLongFormatReport<List<SAS_C_DISAGG_C>>(reportGroup.AgricultureFilenameFOCombinedLF, reportGroup.FOCombined, reportGroup.Agriculture, combinedDisagReportData);
}
}
}
protected void CreateFormatReport<T>(string filename, string disagCategory, string commSubGp, List<T> reportData)
{
using (FileStream fileStream = new FileStream(Server.MapPath(#"~/Includes/") + filename, FileMode.Create))
{
using (StreamWriter writer = new StreamWriter(fileStream))
{
foreach (var value in reportData)
{
string FuturesOnly = "Futures Only, ";
string FOCombined = "Futures and Options Combined, ";
string reportCategory = "";
if (disagCategory == FuturesOnly)
{
reportCategory = FuturesOnly;
}
else if (disagCategory == FOCombined)
{
reportCategory = FOCombined;
}
string row01 = String.Format("{0, -10}{1, 29}{2, 8}", value.MKTTITL.PadRight(120), "Code -", value.Conmkt);
string row02 = String.Format("{0, -10}{1, 7}{2, 14}", "Blah Blah - ", reportCategory, value.DAT1TITL);
string row03 = String.Format("{0, 3}{1, 3}{2, 8:0,0}{3, 3}{4, 8:0,0}{5, 11:0,0}{6, 11:0,0}{7, 11:0,0}{8, 11:0,0}{9, 13:0,0}{10, 11:0,0}{11, 11:0,0}{12, 13:0,0}{13, 10:0,0}{14, 9:0,0}{15, 3}{16, 8:0,0}{17, 10:0,0}", "All",
colon, value.TA01, colon, value.TA02, value.TA03, value.TA04, value.TA05, value.TA06, value.TA07, value.TA08, value.TA09, value.TA10, value.TA11, value.TA12, colon, value.TA15, value.TA16);
string row04 = String.Format("{0, 3}{1, 3}{2, 8:0,0}{3, 3}{4, 8:0,0}{5, 11:0,0}{6, 11:0,0}{7, 11:0,0}{8, 11:0.##}{9, 13:0,0}{10, 11:0,0}{11, 11:0,0}{12, 13:0,0}{13, 10:0,0}{14, 9:0,0}{15, 3}{16, 8:0,0}{17, 10:0,0}", "Old",
colon, value.TO01, colon, value.TO02, value.TO03, value.TO04, value.TO05, value.TO06, value.TO07, value.TO08, value.TO09, value.TO10, value.TO11, value.TO12, colon, value.TO15, value.TO16);
writer.Write(row01);
writer.WriteLine(row02);
writer.WriteLine(row03);
writer.WriteLine(row04);
} //end foreach
writer.Close();
} //end of stream writer
}
}
Thanks for your help.
I managed to solve this problem myself so I'm posting my solution for others that may need the same type of help. The solution is to use Reflection within the foreach iteration.
foreach (var value in ReportData)
{
//Reflection can be used
string TA01 = value.GetType().GetProperty("TA01").GetValue(value).ToString();
//...
//...
//do more stuff/coding...
}
Then in the String.Format change "value.TA01" to "TA01". Do the same for all other variables.
Hope this help.
This code does provide me the values I am wanting in my comboBox, but I am wondering if there is a way to get the viewColumn ID, viewColumnHeader ID, and number of columns in the viewPanel programmatically. The viewPanel is using a JDBCQuery as the datasource.
var itemList:java.util.Vector = new java.util.Vector;
var colID = "viewColumn"; //default id assigned
var colHeaderID = "viewColumnHeader"; //default id assigned
var end = 10; //max # of viewPanel columns
itemList.add("Select Column");
for(x=1;x<end;x++) {
try {
if(getComponent(colID + x) == null) {
throw ("Only " + (x-1) + " columns in ViewPanel");
x=end;
} else {
var disColID = getComponent(colID + x).getColumnName();
}
var disColHeaderID = getComponent(colHeaderID + x).getValue();
itemList.add(disColHeaderID + "|" + disColID);
} catch (e) {
dBar.info(e.toString());
}
}
itemList
The current way is obviously restricted to only 9 columns and ensuring the viewColumn ID and viewColumnHeader ID have a specific naming structure which would be nice to get away from.
All the columns of a view panel can be accessed by getting the child components of view panel using viewPanelObj.getChildren(). The column headers are a part of view column and after you get the handle of view column you can access the header using viewColumnObj.getHeader().
So a sample SSJS code to access all the view columns and view headers would look something like this:
var viewPnl:com.ibm.xsp.component.xp.XspViewPanel = getComponent("viewPanel1");
var list:java.util.List = viewPnl.getChildren();
for (var i=0 ; i<list.size() ; i++) {
var viewCol:com.ibm.xsp.component.xp.XspViewColumn = list.get(i);
var viewHdr:com.ibm.xsp.component.xp.XspViewColumnHeader = viewCol.getHeader();
// Perform required operations on objects of viewCol & viewHdr
}
I am using Lucene in an application. As such I have a form that lets users build a query by selecting what they want to search from dropdowns.
Once a user submits, I build the query and it comes down to something like this:
var formedQuery= string.Empty;
foreach(var field in fields)
{
if (field.name != 'condition so you never know which field from fields will be 1st')
formedQuery += " AND" + field.name + ":" field.value;
}
Now the problem with this is that the statement will begin with ' AND'
Now I usually finish with:
formedQuery = formedQuery.Substring(4) //Trim the first 4 characters
Would fellow programmers usually prefer to do:
var formedQuery= string.Empty;
var i = false;
foreach(var field in fields)
{
if (false &&
field.name != 'condition so you never know which field from fields will be 1st')
{
formedQuery += " AND" + field.name + ":" field.value;
i = true;
}
else
formedQuery += " " + field.name + ":" field.value;
}
Is there another technique people like to use for this sort of thing I am not thinking of?
I prefer the former.
There are two other solutions I use, depending a little on the language. The first is similar to your second one, but just changes the "first-field" check.
var formedQuery = string.Empty;
var and = string.Empty;
foreach(var field in fields)
{
if (field.name != 'condition so you never know which field from fields will be 1st')
{
formedQuery += and + field.name + ":" field.value;
and = " AND";
}
}
But the solution I usually use involves an ordered list. Assuming I can extend your example code in any way that looks sensible:
var formedQuery = list.Empty;
foreach(var field in fields)
{
if (field.name != 'condition so you never know which field from fields will be 1st')
{
formedQuery.push(field.name + ":" field.value);
}
}
formedQuery = formedQuery.join(" AND ");
This also has the advantage of not making lots of unnecessary string copies as your assemble the string (in some languages, this is expensive).
I have always used the former. Mostly because it looks cleaner to me.
Another approach:
query = first_field_name
for every other field besides first:
query = " AND " + field_name