Add 2 or more constructors in kotlin - java

how to add 2 or more constructors ?? i know the use of data class in kotlin, but i am not getting what exactly this keyword is in kotlin and why we have to put anything inside this?
public class Model {
public String mId, mTitle, mDesc;
public Model() {
}
public Model(String mId, String mTitle, String mDesc) {
this.mId = mId;
this.mTitle = mTitle;
this.mDesc = mDesc;
}
public String getmId() {
return mId;
}
public void setmId(String mId) {
this.mId = mId;
}
public String getmTitle() {
return mTitle;
}
public void setmTitle(String mTitle) {
this.mTitle = mTitle;
}
public String getmDesc() {
return mDesc;
}
public void setmDesc(String mDesc) {
this.mDesc = mDesc;
}
}
I know kotlin but not that much.
how i changed
data class model_for_single_row (val mId:String,val mTitle:String,val mDesc:String){
constructor():this()
}
it gives me error to put something inside this. why we use this here and why we should put, and what we should put?

Default value of String in java is null, which isn't the case in Kotlin.
You can make fields nullable and attach their defualt values to null:
data class model_for_single_row(
val mId: String? = null,
val mTitle: String? = null,
val mDesc: String? = null
)
You can call it like:
model_for_single_row()
model_for_single_row("id")
model_for_single_row("id", "title")
model_for_single_row("id", "title", "desc")
model_for_single_row(mTitle = "title")
Parameters not supplied will be null here.

Hope it could be useful, the this keyword is used concerning constructors inside a class :
1 - to delegate from a secondary constructor to the primary constructor, like this :
class Car(val id: String, val type: String) {
constructor(id: String): this(id, "unknown")
}
2 - to delegate from a secondary constructor to another secondary constructor where no primary constructor is present; so here in this example there is a child class with more than one secondary constructor derived from a parent class with more than one secondary constructor and no primary constructor as well:
fun main(args: Array<String>) {
val p1 = AuthLog("Bad Password")
}
open class Log {
var data: String = ""
var numberOfData = 0
constructor(_data: String) {
}
constructor(_data: String, _numberOfData: Int) {
data = _data
numberOfData = _numberOfData
println("$data: $numberOfData times")
}
}
class AuthLog: Log {
constructor(_data: String): this("From AuthLog -> + $_data", 10) {
}
constructor(_data: String, _numberOfData: Int): super(_data, _numberOfData) {
}
}

Related

Setting a default value in a Kotlin data class conditionally

I am trying to implement an interface in Kotlin, and basically what I am trying to do is say: "If the value atb if null/not set, then set it to bugId".
Here is the Kotlin interface I am trying to implement
interface Incident {
#get:NotNull
#get:Past
val incidentDate: LocalDateTime
#get:NotNull
val source: String
#get:NotNull
#get:Positive
val bugId: Int
#get:NotNull
#get:Pattern(
regexp = "FOO|BAZ",
message = "'\${validatedValue}' not allowed. Must be one of : {regexp}"
)
val pillar: String
#get:Positive
val atb: Int
}
And here is how I am trying to implement it:
data class PSR (
#JsonDeserialize(using = DoubleToInt::class)
override val bugId: Int,
#JsonDeserialize(using = EpochToLocalDateTime::class)
override val incidentDate: LocalDateTime,
override val pillar: String,
#JsonDeserialize(using = DoubleToInt::class)
override val atb: Int = bugId,
) : Incident {
override val source: String = "PSR"
}
The problem is I am trying to deserialize this data from JSON and when I do, I get the following (understandable) error:
Instantiation of [simple type, class com.company.models.spreadsheets.psr.PSR] value failed for JSON property atb due to missing (therefore NULL) value for creator parameter atb which is a non-nullable type
at [Source: UNKNOWN; byte offset: #UNKNOWN] (through reference chain: com.company.models.spreadsheets.psr.PSR["atb"])
I've given the equivalent java code below that achieves what I want. How can I do this in Kotlin (and keep the benefits of a data class)?
class PERF implements Incident {
private final LocalDateTime incidentDate;
private final Integer bugId;
private final String pillar;
private final Integer atb;
public PERF(LocalDateTime incidentDate, Integer bugId, String pillar, Integer atb) {
this.bugId = bugId;
this.atb = atb == null ? bugId: atb;
this.incidentDate = incidentDate;
this.pillar = pillar;
}
#NotNull
#Override
public LocalDateTime getIncidentDate() {
return incidentDate;
}
#Override
public int getBugId() {
return bugId;
}
#NotNull
#Override
public String getPillar() {
return pillar;
}
#Override
public int getAtb() {
return atb;
}
#Override
public String getSource() {
return "PERF"
}
}
Assuming you are using Jackson, just create a secondary constructor and mark that as JsonCreator instead. Have the secondary constructor delegate to the primary one.
data class PSR (
override val bugId: Int,
override val incidentDate: LocalDateTime,
override val pillar: String,
override val atb: Int = bugId,
) : Incident {
#JsonCreator
constructor(
#JsonDeserialize(using = DoubleToInt::class)
#JsonProperty("bugId")
bugId: Int,
#JsonDeserialize(using = EpochToLocalDateTime::class)
#JsonProperty("incidentDate")
incidentDate: LocalDateTime,
#JsonProperty("pillar")
pillar: String,
#JsonDeserialize(using = DoubleToInt::class)
#JsonProperty("atb")
atb: Int?,
): this(bugId, incidentDate, pillar, atb ?: bugId)
override val source: String = "PSR"
}

Which design pattern reduces repetition in this validation inputs code

Want to reduce code from these validations, these validators' classes verify and return if inputs are valid or invalid, it's a reduction, I will validate some panels and almost 40 fields. Want to see if there is some pattern to simplify this, code is more than 300 lines which I believe to be a bad practice.
package Validation1;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MinimalReproducibleExampleValidation {
public static void main(String[] args) {
boolean saveToDatabase = true;
String name = "Richard";
String idCard = "123456789";
String address = "Main Street 454";
Entity entity = new Entity ();
/// Name Validation
if (saveToDatabase) {
ValidationEntity nameValidation = new
ValidationEntity(ValidationEntity.Regex.Alphabetic,
name, "ID Card", 0, 13);
saveToDatabase = nameValidation.isValid();
entity.setName(name);
}
/// ID Card Validation
if (saveToDatabase) {
ValidationEntity idCardValidator = new
ValidationEntity(ValidationEntity.Regex.Numerical,
idCard, "ID Card", 0, 13);
saveToDatabase = idCardValidator.isValid();
entity.setIdCard(idCard);
}
/// EMail Validation
if (saveToDatabase) {
ValidationEntity emailValidator = new
ValidationEntity(ValidationEntity.Regex.AlphaNumerical,
address, "Address", 1, 9);
saveToDatabase = emailValidator.isValid();
entity.setAddress(address);
}
// If every field is valid, save
if (saveToDatabase) {
new EntityDao().save(entity);
}
}
}
and:
class ValidationEntity {
private Regex regex;
private String input;
private String errorMessage;
private Integer minimum;
private Integer maximum;
public ValidationEntity(Regex regex, String input, String errorMessage, int minimum, int maximum) {
this.regex = regex;
this.input = input;
this.errorMessage = errorMessage;
this.minimum = minimum;
this.maximum = maximum;
}
public boolean isValid() {
Pattern pattern = Pattern.compile(getRegexFormat(), Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(input);
return matcher.matches();
}
public String getRegexFormat() {
return "^" + regex.getRegex() + "{" + minimum + "," + maximum + "}";
}
and:
public enum Regex {
LowercaseAlphabetic("[a-z]"), UppercaseAlphabetic("[A-Z]"), Numerical("[0-9]"), Alphabetic("[a-zA-Z]"),
AlphaNumerical("^[A-Za-z0-9_ ]*$");
public String regexValue;
Regex(String regexValue) {
this.regexValue = regexValue;
}
}
}
and:
class EntityDao {
public void save(Entity entity) {
System.out.println("Saving the model!");
}
}
and:
class Entity {
private String name;
private String idCard;
private String address;
public void setIdCard(String idCard) {
this.idCard = idCard;
}
public void setName(String name) {
this.name = name;
}
public void setAddress(String address) {
this.address = address;
}
public String getIdCard() {
return idCard;
}
public String getIdName() {
return name;
}
public String getAddress() {
return address;
}
}
We have a repetetive behaviour:
if (saveToDatabase) {
ValidationEntity nameValidation = new
ValidationEntity(ValidationEntity.Regex.Alphabetic,
name, "ID Card", 0, 13);
saveToDatabase = nameValidation.isValid();
entity.setName(name);
// create ValidationEntity object
// check whether entity is valid
// set some attribute value
}
I would suggest:
to collect all validation logic in one place
set some attribute values after validation is completed
and then save to database
By doing the above actions, we will separate our validation logic, variable assignments and saving database. So our code should comply with Single Responsibility principle of SOLID principles.
So let's put repetetive behaviour in some abstraction. I am sorry, I am not Java guy. Let me show via C#. But I've provided comments of how code could look in Java:
public abstract class FieldValidation
{
// I am not Java guy, but if I am not mistaken, in Java,
// if you do not want method to be overriden, you shoud use `final` keyword
public abstract bool IsValid();
}
And its concrete implementations:
public class IdCardFieldValidation : FieldValidation // extends in Java
{
public override bool IsValid() // #Override in Java
{
// your code here:
/*ValidationEntity nameValidation = new
ValidationEntity(ValidationEntity.Regex.Alphabetic,
name, "ID Card", 0, 13);
return nameValidation.isValid();*/
return true;
}
}
public class EmailFieldValidation : FieldValidation // extends in Java
{
public override bool IsValid() // #Override in Java
{
// your code here:
/*ValidationEntity emailValidator = new
ValidationEntity(ValidationEntity.Regex.AlphaNumerical,
address, "Address", 1, 9);
returnr emailValidator.isValid();*/
return true;
}
}
And then we can create a class which will have all validations. And this class will return whether all validations were okay:
public class AllFieldValidations
{
private List<FieldValidation> _fieldValidations = new List<FieldValidation>()
{
new IdCardFieldValidation(),
new EmailFieldValidation()
};
public bool IsValid()
{
foreach (var fieldValidation in _fieldValidations)
{
if (!fieldValidation.IsValid())
return false;
}
return true;
}
}
And then your method will look like this:
AllFieldValidations allFieldValidations = new AllFieldValidations();
bool isAllFieldsValid = allFieldValidations.IsValid();
if (!isAllFieldsValid)
return;
SetAttributes();
SaveToDatabase();
and implementations of other methods:
public void SetAttributes
{
entity.setName(name);
entity.setIdCard(idCard);
entity.setAddress(address);
}
public void SaveToDatabase()
{
new EntityDao().save(entity);
}
So here we've applied Single responsibility principle here of SOLID principles.
I mean we do not have almighty method that has all validations, setting attributes and saving to database.
Pros of this approach:
highly testable code
great separation of concerns
improved readability. We've created methods with self explanatory names

How to write getters and setters in kotlin?

I am new to kotlin and building a quiz app. I don't understand How do I write this java code into Kotlin? Especially the getters and setters? Also how to create both default and parameterized constructor in Kotlin?
What I did is This:
class Question {
var question: String
var opt1: String
var opt2: String
var opt3: String
var answerno: Int
constructor(question: String, opt1: String, opt2: String, opt3: String, answerno: Int) {
this.question = question
this.answerno = answerno
this.opt1 = opt1
this.opt2 = opt2
this.opt3 = opt3
}
}
Java Code Here:
public class Question {
private String question;
private String option1;
private String option2;
private String option3;
private int answerNr;
public Question() {
}
public Question(String question, String option1, String option2, String option3, int answerNr) {
this.question = question;
this.option1 = option1;
this.option2 = option2;
this.option3 = option3;
this.answerNr = answerNr;
}
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
public String getOption1() {
return option1;
}
public void setOption1(String option1) {
this.option1 = option1;
}
public String getOption2() {
return option2;
}
public void setOption2(String option2) {
this.option2 = option2;
}
public String getOption3() {
return option3;
}
public void setOption3(String option3) {
this.option3 = option3;
}
public int getAnswerNr() {
return answerNr;
}
public void setAnswerNr(int answerNr) {
this.answerNr = answerNr;
}
}
In kotlin getters and setters are automatically generated by the compilers, you can write all the variables into the constructor. This will generate all the getter and setters for the fields here.
class Question (
var question: String
var opt1: String
var opt2: String
var opt3: String
var answerno: Int
)
If you want to provide a custom getter or setter, just create property inside the class:
class Question (
question: String
var opt1: String
var opt2: String
var opt3: String
var answerno: Int
) {
var question = question
get() {
// getter code (use field variable here to access this variable)
}
set(value) {
// assign value to field variable, like `field = value`
}
}
You don't need to assign getter setter as it is there by default. You can access them using question.option1.
You can use like this,
class Question(
var question: String = "default value",
var option1: String = "default value",
var option2: String = "default value",
var option3: String = "default value",
var answerNr: Int = 0
)
This way you can assign default values.
I would suggest you read up the kotlin documentation to create a model class. It has some good explanations here.
https://kotlinlang.org/docs/reference/properties.html
Have a look at following plain object class.
class Question {
var question:String
var option1:String
var option2:String
var option3:String
var answerNr:Int = 0
constructor() {}
constructor(question:String, option1:String, option2:String, option3:String, answerNr:Int) {
this.question = question
this.option1 = option1
this.option2 = option2
this.option3 = option3
this.answerNr = answerNr
}
}
If you are looking for the data class then try following way
data class Question (
var question:String,
var option1:String,
var option2:String,
var option3:String,
var answerNr:Int = 0
) {
}
get() = field // getter
set(value) { // setter
field = value
}
Eg:-
get() = question
set(value){
question = value
}
You can avoid getters/setters boilerplate with Kotlin Data classes.
You also can replace constructors with Fabric methods in Companion objects. More on this topic you could find in the book Effective Java "Item 1: Consider static factory methods instead of constructors " And here.
Another useful data classes feature is copy-methods. With them you can avoid creating mutable object. Immutable objects have a lot advantages over mutable. For example it's safe to use immutable objects in multithreading programming.
data class Question(
val question: String,
val opt1: String,
val opt2: String,
val opt3: String,
val answerno: Int
) {
companion object {
// Fabric methods in companion objects as replace to secondary constructors
fun fromQuestion(question: String) = Question(
question = question,
opt1 = "",
opt2 = "",
opt3 = "",
answerno = 0
)
}
}
// Using Companion object fabric method
val myQuestion = Question.fromQuestion("question")
// Avoid mutable objects with copy method
val newQuestion = myQuestion.copy(
question = "New question"
)
If you want absolutely the same structure as in Java class you presented here is the converted solution with all "nullabilities":
class Question {
var question: String? = null
var option1: String? = null
var option2: String? = null
var option3: String? = null
var answerNr = 0
constructor() {}
constructor(
question: String?,
option1: String?,
option2: String?,
option3: String?,
answerNr: Int
) {
this.question = question
this.option1 = option1
this.option2 = option2
this.option3 = option3
this.answerNr = answerNr
}
}
Thanks to #gidds, for pointing out that Kotlin by default generates getters and setters (for mutable properties) for each class property.
Properties are not private and declared as var because:
- (var) your java code had getters and setters for each property;
- (not private) your getters and setters simply return and set values without changing them.
If for example getQuestion and setQuestion used question value to perform some calculations and returned the result of calculations your converted class would look like this:
class Question {
private var question: String? = null
var option1: String? = null
var option2: String? = null
var option3: String? = null
var answerNr = 0
constructor() {}
constructor(
question: String?,
option1: String?,
option2: String?,
option3: String?,
answerNr: Int
) {
this.question = question
this.option1 = option1
this.option2 = option2
this.option3 = option3
this.answerNr = answerNr
}
fun getQuestion(): String {
return question + "value"
}
fun setQuestion(question: String) {
this.question = question + "value"
}
}
That is the most direct conversion.

How to override the #AdminPresentation for existing attributes [Broadleaf Commerce]

I am trying to override the #AdminPresentation of the following attribute defined in ProductImpl:
#Column(name = "DISPLAY_TEMPLATE")
#AdminPresentation(friendlyName = "ProductImpl_Product_Display_Template",
group = GroupName.Advanced)
protected String displayTemplate;
Currently, it is displayed as a text field by default as there is no fieldType attribute provided. But I want to display a dropdown select menu with predefined values such as Product and Plan. Here is what I've tried so far:
I've created a class DisplayTemplateType that implements BroadleafEnumerationType and defined PLAN and PRODUCT enums. Here is the code of that class:
public class DisplayTemplateType implements Serializable, BroadleafEnumerationType {
private static final long serialVersionUID = 7761108654549553693L;
private static final Map<String, DisplayTemplateType> TYPES = new LinkedHashMap<String, DisplayTemplateType>();
public static final DisplayTemplateType PLAN = new DisplayTemplateType("PLAN", "PLAN");
public static final DisplayTemplateType PRODUCT = new DisplayTemplateType("PRODUCT", "PRODUCT");
public static DisplayTemplateType getInstance(final String type) {
return TYPES.get(type);
}
private String type;
private String friendlyType;
public DisplayTemplateType() {
//do nothing
}
public DisplayTemplateType(final String type, final String friendlyType) {
this.friendlyType = friendlyType;
setType(type);
}
#Override
public String getType() {
return type;
}
#Override
public String getFriendlyType() {
return friendlyType;
}
private void setType(final String type) {
this.type = type;
if (!TYPES.containsKey(type)) {
TYPES.put(type, this);
} else {
throw new RuntimeException("Cannot add the type: (" + type + "). It already exists as a type via " + getInstance(type).getClass().getName());
}
}
// equals() and hashCode() implementation is removed for readability
}
Then in applicationContext-admin.xml file, I have added the following override properties:
<mo:override id="blMetadataOverrides">
<mo:overrideItem ceilingEntity="org.broadleafcommerce.core.catalog.domain.Product">
<mo:field name="displayTemplate">
<mo:property name="explicitFieldType" value="BROADLEAF_ENUMERATION"/>
<mo:property name="broadleafEnumeration" value="com.community.core.domain.DisplayTemplateType"/>
</mo:field>
</mo:overrideItem>
</mo:override>
But it didn't change anything. Am I missing something here?
Finally, after trying many things, I came up with a workaround. Instead of going with the XML based approach, I had to extend the ProductImpl class to override #AdminPresentation of its attributes. But for extending I needed to define an #Entity and as a result, I needed to create a useless table to bind to that entity. I know this is not the perfect approach but I couldn't find any better solution for this. Here is my code, so that someone might get help from it in the future:
#Entity
#Immutable
#AdminPresentationMergeOverrides({
#AdminPresentationMergeOverride(name = "displayTemplate", mergeEntries = {
#AdminPresentationMergeEntry(propertyType = PropertyType.AdminPresentation.FIELDTYPE, overrideValue = "BROADLEAF_ENUMERATION"),
#AdminPresentationMergeEntry(propertyType = PropertyType.AdminPresentation.BROADLEAFENUMERATION, overrideValue = "com.community.core.domain.DisplayTemplateType"),
#AdminPresentationMergeEntry(propertyType = PropertyType.AdminPresentation.REQUIREDOVERRIDE, overrideValue = "REQUIRED"),
#AdminPresentationMergeEntry(propertyType = PropertyType.AdminPresentation.DEFAULTVALUE, overrideValue = "PLAN")
})
})
public class CustomProduct extends ProductImpl {
private static final long serialVersionUID = -5745207984235258075L;
}
This is how it is displayed now:

How to invoke getter method for instance that locate inside of another instance

I have some classes like below:
#Getter
#Setter
class Person{
#JsonProperty("cInfo")
private ContactInformation contactInfo;
private String name;
private String position;
}
#Getter
#Setter
class ContactInformation{
#JsonProperty("pAddress")
private Address address;
}
#Getter
#Setter
class Address{
private String street;
private String district;
}
And what I am going to do is writing an Utils method for the Person object that take one parameter which is the attributeName as String and return the getter value for this attribute.
Ex:
attributeName = name -> return person.getName()
attributeName = position -> return person.getPosition()
attributeName = cInfo.pAddress.street -> return person.getContactInfo().getAddress().getStreet()
attributeName = cInfo.pAddress.district -> return person.getContactInfo().getAddress().getDistrict()
Below is what I've done: I loop through all the fields in the Person object and check if the attributeName equal to either the JsonProperty's Name or the Field's Name then I will return this getter.
Object result;
Field[] fields = Person.class.getDeclaredFields();
for (Field field : fields) {
JsonProperty jsonProperty = field.getDeclaredAnnotation(JsonProperty.class);
if (jsonProperty != null && jsonProperty.value().equals(attributeName)) {
result = Person.class.getMethod("get" + capitalize(field.getName())).invoke(person);
} else {
if (field.getName().equals(attributeName)) {
result = person.class.getMethod("get" + capitalize(field.getName()))
.invoke(person);
}
}
}
This worked but only with the fields that locate direct in the Person class, ex: name, position. With the fields inside of contactInfo or address I am still getting stuck there. Can anyone give me some hint here how can I do it?
Thank you!
Because path like a.b.c related to different objects. So you need to. split by point and for each token call get and use obtained result for next token
UPDATE: something like:
private static Object invkGen(Object passedObj, String attributeName) throws Exception {
final String[] split = attributeName.split("\\.");
Object result = passedObj;
for (String s : split) {
if (result == null) {
break;
}
result = invk(result, s);
}
return result;
}
private static Object invk(Object passedObj, String attributeName) throws Exception {
Object result = null;
final Field[] fields = passedObj.getClass().getDeclaredFields();
for (Field field : fields) {
JsonProperty jsonProperty = field.getDeclaredAnnotation(JsonProperty.class);
if (jsonProperty != null && jsonProperty.value().equals(attributeName)) {
result = Person.class.getMethod("get" + capitalize(field.getName())).invoke(passedObj);
} else {
if (field.getName().equals(attributeName)) {
result = passedObj.getClass().getMethod("get" + capitalize(field.getName()))
.invoke(passedObj);
}
}
}
return result;
}

Categories