Hi everyone.
Welcome back.
In this lecture we will look into some of the internals of constructors.
And how can we apply domain validations before constructing this product instance.
Because by default there are constructors generated by the compiler whenever you create a record class.
And those constructors are called canonical constructors, because without the constructor there is
no way we can create objects in Java.
The concept is applicable for records too.
So now in this case for the product, let's say when you are creating a product, you want to make sure
the name is not null or the name is not blank, and the cost should be greater than zero, right.
If you want to apply those kind of validations, what are the options we have?
Now?
Let's quickly jump into it and then explore those concepts.
So the very first thing is we can apply those kind of validations.
So what we need to do we just need to create a product.
But this is not going to be a constructor.
What this is going to be is a simple code block.
So this code block has access to all the parameters that we pass to this specific record class.
So in this case we can apply validations like if name not equal to null and and name is blank.
If the name is blank we want to throw an illegal argument exception.
Right.
So in this case we can do throw new Illegalargumentexception.
And the value is going to be name is not valid okay.
So this is one exception.
The other exception is we want to make sure the cost should not be zero or less than zero.
In those kind of scenarios.
What we can do in this case we can do if cost dot compare to because that's a function that we can use
in order to compare the values that are part of the cost.
Right.
So in this case it can be bigdecimal dot zero is less than or equal to zero.
So in this kind of scenarios we will make sure that the cost that's been passed to this product instance
is always greater than zero.
So in this case we also throw the illegal argument exception.
Okay.
But in this case it's going to be cast.
Value is not valid.
So these are the two validations that we have for the product record class.
And this is how you can actually apply exceptions before constructing the object.
Now let's go ahead and test this one.
So what we are going to do we are going to be testing the name being not valid first.
And then we will test the cast being not valid.
So in this case I am going to name this one as name.
Not valid.
Okay.
So in this case I'm going to pass the value as empty over here.
And the way we are going to call this, it's going to be a little different because in JUnit five there
is a handy way to test this one.
So in this case what we are going to do we are going to call assert throws.
So we are going to assert what that exception is thrown right.
So in this case we can call assert throws.
And then we can call out which exceptions we are expecting as part of this call.
So in this case we are expecting an illegal argument exception.
Right.
So that's the exception which is thrown from here.
Let's copy this one and then put it over here or dot class.
Okay.
And then what we do is we provide a supplier.
So the way you provide the supplier is by providing a lambda right.
So we are using the lambda syntax to provide the supplier.
And then we can actually copy this one and then put this one over here.
So what this is going to do is that when this code gets executed while we run this test case, this
code is going to throw an exception.
And that will be caught by this specific assert throws block.
And that exception is going to be illegal argument exception.
If there is a match then we will have access to that exception too.
So the way we do it is by calling where exception.
There you go.
So in the then block what we can do.
We can actually check what the actual message is.
So in this case the message is going to be name is not valid.
Let's copy it over here and then put it over here.
And then we are going to be calling exception dot message.
So this is how you test the exception scenario in JUnit five.
So what we are doing is that we are calling the product record class.
Basically we are creating an instance of the product record class, but we are passing the name as empty
string.
So in this case if the name is blank it's going to throw an illegal argument exception.
Let's go ahead and execute this test case.
There you go.
The test case passed.
So this means this is working as expected.
Now the next step is to write a test case that's going to validate the cost right.
So let's go ahead and copy this one and then create another test case.
Let's name this one as cost not valid.
So it's going to be cost not valid.
And then in the place of this one this is going to be iPhone again which means we are passing a valid
product name.
But the value is going to be negative.
So the cost represents -9.99999 which is not a valid value because we have a check over here that's
going to throw an illegal argument exception in this case we can actually call cast is not valid.
Okay.
So now let's go ahead and execute this specific test case.
There you go.
This test case also passed.
Now what I wanted to do I want to execute the whole test class to make sure that all the test cases
are succeeding without any issues.
So the introduction of these validations did not break the positive test case.
So if we pass a valid name and the valid cast, then the test case is going to execute as expected.
Now what I wanted to show you is that what are the options when it comes to creating a custom constructor.
So let's assume the type is not something which is always known.
If the type is not passed, then we would like to assign some generic type name like general, right.
So if the type is not passed we would like to assign the type to be general, because in this case for
iPhone we are passing the type as electronics, right.
So from a product perspective we might not know the type all the time.
So that's what this domain represents.
Okay.
So in this case what we will do is we will create the public and then provide the class name.
And then we are going to be passing the name and cast.
Because this is a mandatory value which will always be passed.
Okay.
And then when this happens if you take a look at the error over here, non-canonical record constructor
must delegate to another constructor.
What this means is that it needs to definitely call the canonical constructor.
So in this case, the way you call it is by calling this dot or this name cast.
And then we can assign the generic type as general.
Okay.
So this is how you create a custom constructor.
Now let us go ahead and quickly write a test case to make sure this is going to work as expected.
So in this case let's copy this one and then put it at the bottom.
And we can name this one as create product custom constructor.
Okay.
And then I'm not going to pass the type right.
So in this case this is going to make sure the call goes to the custom constructor that we created.
So now the call goes to this one.
But in the case of the type the type is going to be general because that's a default type that gets
assigned if you don't pass a type.
Now if I go ahead and execute this test case.
So this is going to give me a green signal to there you go.
So we got the green signal as expected.
And if you take a look at the product the product type is assigned as general.
And this particular code is being invoked by the this block.
So any time you create a custom constructor, calling the canonical constructor using the this operator
is a must, otherwise the compiler won't be happy.
I hope you all had fun coding this.
Custom validations and how to create custom constructors.
So these are some of the advanced concepts.
You will be actually implementing it for different use cases, but it is good to be aware that you have
all these additional concepts that are available with record classes.
This marks the end of this lecture.
Thank you for watching.