NoSuchMethodError. The method "add" was called on null even after initializing List - list

I have created a TextFormField in flutter. I have a class named ParticipantsData with a few properties listed. I can access and store values in all of those properties by making an object of ParticipantsData class in another class named "RegistrationForm". However I am unable to store data in the properties that are of type List even after having initialized them.
I have tried:
- List.filled()
- =[]
- =[""]
- List.generate()
- List()
- List<String>()
- List<String>(length)
I have changed my code multiple times over and tried many methods but nothing seems to work. I don't post here much because I usually find solutions on stackoverflow but this time I couldn't find anything.
Unable to post the whole code because it is too long. Below is the relevant code:
ParticipantsData class:
class ParticipantsData {
List name = []; //members
bool paymentstatus = false; //payment
String email = ""; //email
String address = ""; //address
List contact = []; //contact
String collegename = ""; //collegename
String password = ""; //password
String teamname = ""; //teamname
var modules = List<String>(6); //modules
ParticipantsData({
this.name,
this.email,
this.contact,
this.collegename,
this.address,
this.modules,
this.password,
this.paymentstatus,
this.teamname,
});
}
Below is the relevant code for Register class:
class _RegistrationForm extends State<RegistrationForm> {
final ParticipantsData data = new ParticipantsData();
//This is the onSaved method of a TextFormField, which is in a loop.
(String value) { //Tried this...
data.name[i + 1] = value;
print('${data.name[i + 1]}');
}),
(String value) { //And this too...
data.name.add(value);
print('${data.name[i + 1]}');
}),

The assigned values become null when initialized inside the constructor. If you don't include the fields in the constructor, they will not reset to null.
However, you may want to assign the values in the constructor and want some default value if the field is not provided while creating the instance. Here is how to do so:
class MyClass {
// Don't initialize here
List x;
int y;
MyClass({
this.x,
this.y = 10, // If y is not assigned, it will take a default value of 10
}) {
// Constructor body
this.x = this.x ?? []; // If x is not assigned, it will take a value of []
}
}
Notice that y can be provided with the default value directly as 10 is a constant value. You can only assign constant default values in the constructor parameter list. Since [ ] is not a constant expression or value, it can't be directly assigned as the default value hence, you need to define the constructor body assigning x = [ ] if x is null.
this.x = this.x ?? [];
You can initialize the others in a similar way.

Related

How to make a list of variables in flutter?

I want to create a list in flutter that contains variable. Now when I am trying to edit the contents of the list, it actually gets stored in the list itself. For eg.,
static var _ratingSelected = "";
static var _disconnectSelected = "";
static var _uTypeSelected = "";
List finalSelectedList = [_uTypeSelected,_disconnectSelected,_ratingSelected];
This is my list, when I will edit the list, like,
finalSelectedList[0] = "Main";
The output list will be like
finalSelectedList = ["Main",_disconnectSelected,_ratingSelected];
It will edit the finalSelectedList[0] position of the list but not the variable _uTypeSelected. Is there any way so that the value gets stored in the variable _uTypeSelected and not at the position finalSelectedList[0]?
There is no way to do that. If you use finalSelectedList[0].someProp = "Main"; where the variables are instances of some classes that have a someProp property, then it would work, because there is an additional abstraction. Strings are primitive values and copied by value when added to a list and therefore there is no connection left between list entry and variable.
class Foo {
Foo(this.someProp);
String someProp;
}
static var _ratingSelected = Foo("");
static var _disconnectSelected = Foo("");
static var _uTypeSelected = Foo("");
List finalSelectedList = [_uTypeSelected,_disconnectSelected,_ratingSelected];
finalSelectedList[0].someProp = "Main";

parse and replace a list of object in kotlin

I am currently having a list of obeject defined as:
fun updateList(tools: List<Tool>, updateTools: List<Updated>){
... code below
}
the Tool data class is defined as:
data class Tool(
var id: String = ""
var description: String = ""
var assignedTo: String = ""
)
the Updated data class is defined as:
data class Updated(
var id: String = ""
var assignedTo: String = ""
)
Basically, I parse the list updateTools and if I found a id match in tools, I update the assignedTo field from the Tool type object from tools by the one from updateTools
fun updateList(tools: List<Tool>, updateTools: List<Updated>){
updateTools.forEach{
val idToSearch = it.id
val nameToReplace = it.name
tools.find(){
if(it.id == idToSearch){it.name=nameToReplace}
}
}
return tools
}
it's not working but I do not see how to make it easier to work. I just started kotlin and I feel that it's not the good way to do it
any idea ?
Thanks
First of all:
you're not assigning assignedTo, you're assigning name...
in the predicate passed to find, which
should only return a Boolean value to filter elements, and
should probably not have any side effects,
those should be done later with a call to i.e. forEach.
Additionally, your constructor parameters to the data class are normal parameters, and as such, need commas between them!
Your last code block, corrected, would be:
updateTools.forEach {
val idToSearch = it.id
val nameToReplace = it.name
tools.find { it.id == idToSearch }.forEach { it.assignedTo = nameToReplace }
}
return tools
I'd do it like this (shorter):
updateTools.forEach { u -> tools.filter { it.id == u.id }.forEach { it.assignedTo = u.name } }
This loops through each update, filters tools for tools with the right ID, and sets the name of each of these tools.
I use forEach as filter returns a List<Tool>.
If you can guarantee that id is unique, you can do it like this instead:
updateTools.forEach { u -> tools.find { it.id == u.id }?.assignedTo = u.name }
firstOrNull returns the first element matching the condition, or null if there is none. Edit: it seems find is firstOrNull - its implementation just calls firstOrNull.
The ?. safe call operator returns null if the left operand is null, otherwise, it calls the method.
For = and other operators which return Unit (i.e. void, nothing), using the safe call operator simply does nothing if the left operand is null.
If we combine these, it effectively sets the name of the first element which matches this condition.
First, you're missing comma after properties in your data classes, so it should be:
data class Tool(
var id: String = "",
var description: String = "",
var assignedTo: String = ""
)
data class Updated(
var id: String = "",
var assignedTo: String = ""
)
As for second problem, there're probably number of ways to do that, but I've only corrected your idea:
fun updateList(tools: List<Tool>, updateTools: List<Updated>): List<Tool> {
updateTools.forEach{ ut ->
tools.find { it.id == ut.id }?.assignedTo = ut.assignedTo
}
return tools
}
Instead of assigning values to variables, you can name parameter for forEach and use it in rest of the loop.

Univocity - parse each TSV file row to different Type of class object

I have a tsv file which has fixed rows but each row is mapped to different Java Class.
For example.
recordType recordValue1
recordType recordValue1 recordValue2
for First row I have follofing class:
public class FirstRow implements ItsvRecord {
#Parsed(index = 0)
private String recordType;
#Parsed(index = 1)
private String recordValue1;
public FirstRow() {
}
}
and for second row I have:
public class SecondRow implements ItsvRecord {
#Parsed(index = 0)
private String recordType;
#Parsed(index = 1)
private String recordValue1;
public SecondRow() {
}
}
I want to parse the TSV file directly to the respective objects but I am falling short of ideas.
Use an InputValueSwitch. This will match a value in a particular column of each row to determine what RowProcessor to use. Example:
Create two (or more) processors for each type of record you need to process:
final BeanListProcessor<FirstRow> firstProcessor = new BeanListProcessor<FirstRow>(FirstRow.class);
final BeanListProcessor<SecondRow> secondProcessor = new BeanListProcessor<SecondRow>(SecondRow.class);
Create an InputValueSwitch:
//0 means that the first column of each row has a value that
//identifies what is the type of record you are dealing with
InputValueSwitch valueSwitch = new InputValueSwitch(0);
//assigns the first processor to rows whose first column contain the 'firstRowType' value
valueSwitch.addSwitchForValue("firstRowType", firstProcessor);
//assigns the second processor to rows whose first column contain the 'secondRowType' value
valueSwitch.addSwitchForValue("secondRowType", secondProcessor);
Parse as usual:
TsvParserSettings settings = new TsvParserSettings(); //configure...
// your row processor is the switch
settings.setProcessor(valueSwitch);
TsvParser parser = new TsvParser(settings);
Reader input = new StringReader(""+
"firstRowType\trecordValue1\n" +
"secondRowType\trecordValue1\trecordValue2");
parser.parse(input);
Get the parsed objects from your processors:
List<FirstRow> firstTypeObjects = firstProcessor.getBeans();
List<SecondRow> secondTypeObjects = secondProcessor.getBeans();
The output will be*:
[FirstRow{recordType='firstRowType', recordValue1='recordValue1'}]
[SecondRow{recordType='secondRowType', recordValue1='recordValue1', recordValue2='recordValue2'}]
Assuming you have a sane toString() implemented in your classes
If you want to manage associations among the objects that are parsed:
If your FirstRow should contain the elements parsed for records of type SecondRow, simply override the rowProcessorSwitched method:
InputValueSwitch valueSwitch = new InputValueSwitch(0) {
#Override
public void rowProcessorSwitched(RowProcessor from, RowProcessor to) {
if (from == secondProcessor) {
List<FirstRow> firstRows = firstProcessor.getBeans();
FirstRow mostRecentRow = firstRows.get(firstRows.size() - 1);
mostRecentRow.addRowsOfOtherType(secondProcessor.getBeans());
secondProcessor.getBeans().clear();
}
}
};
The above assumes your FirstRow class has a addRowsOfOtherType method that takes a list of SecondRow as parameter.
And that's it!
You can even mix and match other types of RowProcessor. There's another example here that demonstrates this.
Hope this helps.

Change value of parameter in NSubstitute

I have this method to mock with NSubstitute:
public T VoerStoredProcedureUit<T>(string naam, params SqlParameter[] parameters)
The test method using it sends 2 SqlParameters to this method. VoerStoredProcedureUit is supposed to change the values of these parameters so the tested method can extract that.
I created the following with NSubstitute:
SqlParameter[] param =
{
new SqlParameter("#pat_id", SqlDbType.BigInt) {Direction = ParameterDirection.Output, Value = "Melding"},
new SqlParameter("#Melding", SqlDbType.VarChar, 4096) {Direction = ParameterDirection.Output, Value = 2}
};
productieVerbinding.VoerStoredProcedureUit<PatientNieuwResultaat>(Arg.Any<string>(),
Arg.Any<SqlParameter[]>()).ReturnsForAnyArgs(x =>
{
x[1] = param;
return PatientNieuwResultaat.Succes;
});
The setup however rises an exception:
A first chance exception of type 'NSubstitute.Exceptions.ArgumentIsNotOutOrRefException' occurred in NSubstitute.dll
Additional information: Could not set argument 1 (SqlParameter[]) as it is not an out or ref argument.
How do you return a value if the method uses implicitly by reference values?
If I understand your question correctly, you're trying to return the contents of param when VoerStoredProcedureUit<PatientNieuwResultaat> is called.
In ReturnsForAnyArgs, x[1] refers to the second parameter which is an SqlParameter[]. This isn't a ref/out parameter so you can't reassign it in the caller, which is why you get an error. Instead, you need to copy the elements from your template, into the supplied array. Something like this:
productieVerbinding.VoerStoredProcedureUit<PatientNieuwResultaat>(Arg.Any<string>(),
Arg.Any<SqlParameter[]>()).ReturnsForAnyArgs((x) =>
{
for (int i = 0; i < param.Length; i++)
{
((SqlParameter[])x[1])[i] = param[i];
}
return PatientNieuwResultaat.Succes;
});
You could obviously remove the for loop, since you know how many parameters you need to copy...
productieVerbinding.VoerStoredProcedureUit<PatientNieuwResultaat>(Arg.Any<string>(),
Arg.Any<SqlParameter[]>()).ReturnsForAnyArgs((x) =>
{
((SqlParameter[])x[1])[0] = param[0];
((SqlParameter[])x[1])[1] = param[1];
return PatientNieuwResultaat.Succes;
});
I found a working solution. Assigning a new variable to the parameters did't work somehow, but changing them does. Also, the second of the method parameter is an array, so it should be treated as such.
productieVerbinding.VoerStoredProcedureUit<PatientNieuwResultaat>(Arg.Any<string>(),
Arg.Any<SqlParameter[]>()).ReturnsForAnyArgs(x =>
{
paramPatId = ((SqlParameter[])x[1])[0];
paramMelding = ((SqlParameter[])x[1])[1];
paramPatId.Value = (long)2;
paramMelding.Value = "Melding";
return PatientNieuwResultaat.Succes;
});

AS3/Regular Expressions - Replacing segments of a string

I have absolutely no knowledge in Regex whatsoever. Basically what I'm trying to do is have an error class that I can use to call errors (obviously) which looks like this:
package avian.framework.errors
{
public class AvError extends Object
{
// errors
public static const LAYER_WARNING:String = "Warning: {0} is not a valid layer - the default layer _fallback_ has been used as the container for {1}.";
/**
* Constructor
* Places a warning or error into the output console to assist with misuse of the framework
* #param err The error to display
* #param params A list of Objects to use throughout the error message
*/
public function AvError(err:String, ...params)
{
trace(err);
}
}
}
What I want to be able to do is use the LAYER_WARNING like this:
new AvError(AvError.LAYER_WARNING, targetLayer, this);
And have the output be something along the lines of:
Warning: randomLayer is not a valid layer - the default layer _fallback_ has been used as the container for [object AvChild].
The idea is to replace {0} with the first parameter parsed in ...params, {1} with the second, etc.
I've done a bit of research and I think I've worked out that I need to search using this pattern:
var pattern:RegExp = /{\d}/;
You can use StringUtil
var original:String = "Here is my {0} and my {1}!";
var myStr:String = StringUtil.substitute(original, ['first', 'second']);
Using the g flag in RegExp you can create an array containing all of your {x} matches, then loop through this array and replace each of the matches with the appropriate parameter.
Code:
var mystring:String = "{0} went to {1} on {2}";
function replace(str:String, ...params):String
{
var pattern:RegExp = /{\d}/g;
var ar:Array = str.match(pattern);
var i:uint = 0;
for(i; i<ar.length; i++)
{
str = str.split(ar[i]).join(params[i]);
}
return str;
}
trace(replace(mystring, "marty", "work", "friday")); // marty went to work on friday
i'm assuming you want to have several static constants with varying replacement instances ({0}, {1}, {2}, etc.) in each string constant.
something like this should work - sorry, it's untested:
public function AvError(err:String, ...params)
{
var replacementArray:Array = err.match(new RegExp("{\\d}", "g"));
for (var i:int = 0, i < replacementArray.length, i++)
err = err.replace(new RegExp(replacementArray[i], "g"), params[i]);
trace(err);
}
if you do have several static constants with varying replacement instances, you'll want to check for an appropriate matching amount of …params that are passed.