How to use sealed classes in Android using Kotlin? - sealed-class

I am not able to understand how/when to use sealed classes in Android using Kotlin. I have read the docs but still I am getting confused about its' structure and how to use it. It'd of great help if someone could help me understand this.

Sealed classes allow us to represent hierarchies in a more flexible way. It’s also more readable and is used for better state management.
Child-classes of Sealed class, can be of any type, like: data class, object class, any regular class, or even another sealed class.
This is how we define a sealed class in Android using Kotlin:
sealed class UiState {
object Loading : UiState()
data class Success(val successMessage: String) : UiState()
data class Error(val error: Throwable?) : UiState()
}
Let’s understand this part of the code:
object Loading : UiState() : declared this as an object, as we don’t need to know anything else at this stage.
data class Success(val successMessage: String) : UiState() : declared as data class, as we need the message when we got Success state.
data class Error(val error: Throwable?) : declared this as data class, as we need the Throwable when we got Error state.
Notice how we have used object Loading : UiState(). We are using the same sealed class name as the return type of “Loading” object.
This says, that the “Loading” object belongs to “UiState” sealed class.
This is same for Success and Error states as well.
We can then use this sealed class as the following:
fun observeUiStates(uiState: UiState) = when(uiState) {
UiState.Loading -> println("Loading...Please wait.")
is UiState.Success -> println(uiState.successMessage)
is UiState.Error -> println(uiState.errorMessage)
}
In this aforementioned block of code we are passing the UiState sealed class as a parameter to observeUiStates() method and then by using when we are checking which is the current state of the app and then we will be handling the states accordingly.
Here for the sake of this example, I am just printing the result in the console.
Sealed classes, best work with Model-View-Intent pattern in Android by using RxJava.
By using them, we will now be able to observe to the state changes.
Whenever there is a new state of the app, this observeUiStates() method will give us that specific state only.
To keep it simple for this specific example, I am calling this method from main(). See the code below:
fun main() {
observeUiStates(UiState.Loading)
observeUiStates(UiState.Success("The Ui has returned success state.”))
}
This will print the following in the console:
Loading...Please wait.
The Ui has returned success state.

Related

How to include a nested PropertyBusinessObject in a PropertyBusinessObject json?

My app contains several PropertyBusinessObject entities, and most of them have nested PropertyBusinessObject objects as properties.
For instance, a Note has a parent User which had written the note, so the Note entity contain a Property<User, Note> which is instantiated with the User.class and the name of the property.
Here is the code of the Note Entity:
public class Note extends AbstractEntity
{
public final Property<User, Note> author = new Property<>("author", User.class);
public final Property<String, TarotNote> text = new Property<>("text");
public Note() {}
}
AbstractEntity implements the PropertyBusiness interface and define the methods to be overridden by the entities to properly implements the interface.
And here is the result JSON from PropertyIndex.toJson:
{
"author": "our.app.backend.entity.User#77203809",
"text": "test"
}
Do I need to override the toString method of all my entities to be sure to not have this behavior (seems to be the wrong way...) ? Or (I hope) is there another way?
For your information, the parsing of the Json issued from the server works perfectly fine with nested entities.
This seems like a logic bug in the JSON generation code, I've added code to fix this here: https://github.com/codenameone/CodenameOne/commit/34447f62971d8bb696116f02c97bac9b70de89b6

Use of Wrapper class for deserialization in callout?

I found the following use of a wrapper class, and was wondering if it is a good practice or whether its just duplication of code for no reason.
//Class:
public class SomeClass{
public Integer someInt;
public String someString;
}
//Callout Class:
public class CalloutClass{
public SomeClass someMethod(){
//...code to do a callout to an api
SomeClass someClassObj = (SomeClass)JSON.Deserialize(APIResponse.getBody(), SomeClass.class);
return someClassObj;
}
}
//Controller:
public class SomeController {
public SomeController(){
someClassObj = calloutClassObj.someMethod();
SomeWrapper wrapperObj = new SomeWrapper();
for(SomeClass iterObj : someClassObj){
wrapperObj.someWrapperInt = iterObj.someInt;
wrapperObj.someWrapperString = iterObj.someString;
}
}
public class someWrapper{
public Integer someWrapperInt{get;set;}
public String someWrapperString{get;set;}
}
}
The wrapper class "someWrapper" could be eliminated if we just use getters and setters ({get;set;}) in "SomeClass."
Could anyone explain if there could be a reason for following this procedure?
Thanks,
James
My assumption (because, code in controller is extra pseudo) is
SomeClass is a business entity, purpose of which is to store/work with business data. By work I mean using it's values to display it (using wrapper in controller), to calculate smth in other entities or build reports... Such kind of object should be as lightweight as possible. You usually iterate through them. You don't need any methods in such kind of objects. Exception is constructor with parameter(s). You might want to have SomeObject__c as parameter or someWrapper.
someWrapper is a entity to display business entity. As for wrapper classes in controllers. Imagine, that when you display entity on edit page and enter a value for someWrapperInt property, you want to update someWrapperString property (or you can just put validation there, for example, checking if it is really Integer). Usually, as for business entity, you don't want such kind of functionality. But when user create or edit it, you may want smth like this.

How to get Apex class that implements the Schedulable interface?

I have many classes that implement Schedulable Interface. I want to schdule multiple Apex classes at a time through an another apex class. So I need to query all the classes that are implement Schedulable interface.
I am using the following code snipet to achieve this, but I am getting a compiler error like below
ERROR:
"You must select an Apex class that implements the Schedulable interface. at line 127 column 13"
CODE:
list<ApexClass> listClasses;
String input='0 0 8 13 2 ?';
listClasses=[Select Id, Name,body from ApexClass]
for(ApexClass a:listClasses){
system.schedule(a.Name+' AutoScheduler', input, a);
}
Question:
How do I query all the apex class which implement schedulable interface? So that I can directly pass it to system.schedule() method.
DIFFERENT TRY:
When after getting this error I tried to query only one apex class(Known Class) which implements schedulable interface. Again no use. Please see the below snipet for the different try
CODE:
list<ApexClass> listClasses;
String input='0 0 8 13 2 ?';
//Retriving only one class of Name='SchedularTest'
listClasses=[Select Id, Name,body from ApexClass where Name ='SchedularTest']
for(ApexClass a:listClasses){
system.schedule(a.Name+' AutoScheduler', input, a);
}
ERROR:
"You must select an Apex class that implements the Schedulable interface. at line 127 column 13"
Thanks in advance
Satheeskumar
I'd say the error message is quite clear?
The last parameter you're passing to System.schedule has to be a new object. New instance of the class. What you're passing is the metadata information about the class, it's body etc... This stuff can't be "run" like that.
I'm going to bet that system.schedule('SchedulerTest AutoScheduler', input, new SchedulerTest()); will work OK? If it doesn't - make sure the class compiles OK and maybe also whether it is marked as valid.
See? how do you expect something that represents a row in the database / file on disk to "work" like an object of the class?
If you need to create a new object of given class having only this class' name - you might want to check Type methods.
String className = 'SchedulerTest';
Type t = Type.forName(className);
System.schedule(className, '0 0 8 13 2 ?', (Schedulable)t.newInstance());
This makes a new object (it's actually a generic Object) and then you cast it to something that's acceptable for the method. You'll get a runtime failure if the class doesn't implement the interface:
System.TypeException: Invalid conversion from runtime type
SchedulerTest to system.Schedulable

How to know what class is being deserialized in JackSon Deserializer?

I'm using app engine datastore so I have entity like this.
#PersistenceCapable
public class Author {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
#JsonProperty("id")
#JsonSerialize(using = JsonKeySerializer.class)
#JsonDeserialize(using = JsonKeyDeserializer.class)
private Key key;
....
}
When the model is sent to view, it will serialize the Key object as an Id value. Then, if I send data back from view I want to deserialize the Id back to Key object by using JsonKeyDeserializer class.
public class JsonKeyDeserializer extends JsonDeserializer<Key> {
#Override
public Key deserialize(JsonParser jsonParser, DeserializationContext deserializeContext)
throws IOException, JsonProcessingException {
String id = jsonParser.getText();
if (id.isEmpty()) {
return null;
}
// Here is the problem because I have several entities and I can't fix the Author class in this deserializer like this.
// I want to know what class is being deserialized at runtime.
// return KeyFactory.createKey(Author.class.getSimpleName(), Integer.parseInt(id))
}
}
I tried to debug the value in deserialize's parameters but I can't find the way to get the target deserialized class. How can I solve this?
You may have misunderstood the role of KeySerializer/KeyDeserializer: they are used for Java Map keys, and not as generic identifiers in database sense of term "key".
So you probably would need to use regular JsonSerializer/JsonDeserializer instead.
As to type: it is assumed that handlers are constructed for specific types, and no extra type information is passed during serialization or deserialization process: expected type (if handlers are used for different types) must be passed during construction.
When registering general serializers or deserializers, you can do this when implementing Module, as one of the arguments is type for which (de)serializer is requested.
When defining handlers directly for properties (like when using annotations), this information is available on createContextual() callback of interface ContextualSerializer (and -Deserializer), if your handler implements it: BeanProperty is passed to specify property (in this case field with annotation), and you can access its type. This information needs to be stored to be used during (de)serialization.
EDIT: as author pointed out, I actually misread the question: KeySerializer is the class name, not annotation.

Can someone explain the magic going on in Prism's resolve<> method?

I've got a CustomersModule.cs with the following Initialize() method:
public void Initialize()
{
container.RegisterType<ICustomersRepository, CustomersRepository>(new ContainerControlledLifetimeManager());
CustomersPresenter customersPresenter = this.container.Resolve<CustomersPresenter>();
}
The class I resolve from the container looks like this:
class CustomersPresenter
{
private CustomersView view;
private ICustomersRepository customersRespository;
public CustomersPresenter(CustomersView view,
ICustomersRepository customersRepository,
TestWhatever testWhatever)
{
this.view = view;
this.customersRespository = customersRepository;
}
}
The TestWhatever class is just a dummy class I created:
public class TestWhatever
{
public string Title { get; set; }
public TestWhatever()
{
Title = "this is the title";
}
}
Yet the container happily resolves CustomersPresenter even though I never registered it, and also the container somehow finds TestWhatever, instantiates it, and injects it into CustomersPresenter.
I was quite surprised to realize this since I couldn't find anywhere in the Prism documentation which explicitly stated that the container was so automatic.
So this is great, but it what else is the container doing that I don't know about i.e. what else can it do that I don't know about? For example, can I inject classes from other modules and if the modules happen to be loaded the container will inject them, and if not, it will inject a null?
There is nothing magical going on. You are specifying concrete types, so naturally they are resolvable, because if we have the Type object, we can call a constructor on it.
class Fred { };
Fred f1 = new Fred();
Type t = typeof(Fred);
Fred f2 = (Fred)t.GetConstructor(Type.EmptyTypes).Invoke(null);
The last line above is effectively what happens, the type t having been found by using typeof on the type parameter you give to Resolve.
If the type cannot be constructed by new (because it's in some unknown separate codebase) then you wouldn't be able to give it as a type parameter to Resolve.
In the second case, it is constructor injection, but it's still a known concrete constructable type. Via reflection, the Unity framework can get an array of all the Types of the parameters to the constructor. The type TestWhatever is constructable, so there is no ambiguity or difficulty over what to construct.
As to your concern about separate modules (assemblies), if you move TestWhatever to another assembly, that will not change the lines of code you've written; it will just mean that you have to add a reference to the other assembly to get this one to build. And then TestWhatever is still an unambiguously refeferenced constructable type, so it can be constructed by Unity.
In other words, if you can refer to the type in code, you can get a Type object, and so at runtime it will be directly constructable.
Response to comment:
If you delete the class TestWhatever, you will get a compile-time error, because you refer to that type in your code. So it won't be possible to get a runtime by doing that.
The decoupling is still in effect in this arrangement, because you could register a specific instance of TestWhatever, so every call to Resolve<TestWhatever>() will get the same instance, rather than constructing a new one.
The reason this works is because Unity is designed for it. When you Resolve with a concrete type, Unity looks to see if it can resolve from the container. If it cannot, then it just goes and instantiates the type resolving it's dependencies. It's really quite simple.

Resources