Kotlin cannot access protected abstract method - kotlin

I have the following classes structure:
abstract class Abstr{
protected abstract fun m()
}
class Child : Abstr(){
private val subChild: Abstr = Child()
override fun m() = subChild.m()// Error:(12, 18) Kotlin: Cannot access 'm': it is protected in 'Abstr'
}
I got an exception Kotlin: Cannot access 'm': it is protected in 'Abstr'
It little bit confusing, because the same structure is legal for java.
According to kotlin docs
protected — visible inside this class only + visible in subclasses too;
Is it bug or expected behavior?

It is designed behavior
Protected modifier in Kotlin similar to Java, but has additional restrictions.
Protected in Java:
Visible for inheritance
Visible in package
Protected in Kotlin:
Visible for inheritance
So, according to the code in question we cannot access protected method
class Child : Abstr(){
private val subChild: Abstr = Child()
override fun m() = subChild.m() //Trying to access not inherited method
}
There is similar restriction in Java, when we trying to access protected member from another package:
// FILE: a/SuperClass.java
package a;
public class SuperClass {
protected void superFunction() {}
}
// FILE: b/ChildClass.java
package b;
public class ChildClass extends SuperClass {
void testFunction() {
((SuperClass) new ChildClass()).superFunction(); // ERROR: superFunction() has protected access in a.SuperClass
}
}
There is answer in issue tracker from Kotlin team:
https://youtrack.jetbrains.com/issue/KT-21048

The current behavior is by design.
By calling subChild.m() you're trying to access an instance of Abstr from outside the object, so protected access prevents you from doing this.
Let me show you a short example to clarify the case
abstract class ParentCl {
protected var num = 1
protected open fun m(){
}
}
class ChildCl : ParentCl() {
private val a0 : ParentCl = ChildCl()
override fun m() {
super.m() // 1-st case
num = 2 // 2-nd case
a0.m() // 3-rd case
}
}
You're calling the protected ParentCl's fun from the child class. It will work fine.
You're modifying of protected variable from the child class. It will work fine.
You're calling the protected fun outside the context of the child class. This will not work.
Depends on what was your goal there are two solutions:
If you wanted to call m() from ParentCl you need to change the visibility from protected to internal or public.
If you wanted to call m() from the child class you need to declare the variable without the explicit type of its parent: private val subChild = Child().
Note: in case you will use m() from other children of ParentCl you need to enlarge the visibility scope inside child class: public override fun m() {...}

It's possible a bug.
When i added {} everything became ok.
abstract class Abstr{
protected abstract fun m()
}
class Child : Abstr(){
private val subChild: Abstr = Child()
override fun m() {
subChild.m() // Compiles fine
}
}
Create issue on https://discuss.kotlinlang.org/
or write on Slack
http://slack.kotlinlang.org/

protected — same as private + visible in subclasses too;
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(getLayoutResId())
}
protected open fun getPageTitle() = SpannableString(getString(R.string.app_name))
}
In your sub class
class EditProfileActivity : BaseActivity() {
override fun getPageTitle(): SpannableString = SpannableString(getString(R.string.edit_profile))
}
See the doc for more details
visibility-modifiers
Classes

Related

Private Delegated method

I am using class delegation in Kotlin and wondering if it is possible to make the delegated method private in Kotlin
interface A{
fun test(name: String)
}
class A1:A{
fun test(name: String): String = name
}
interface C{
fun myTest(name: String)
}
class C1(a:A){
fun myTest(name: String) = a.test(name)
}
class B(a:A): C by C1(a) {
// I can call "mytest" here
fun anotherMethod() = myTest("hi")
//But I want to make "myTest" private
}
val b = B(A1())
//This should not be possible
//b.myTest()
Interface is used to expose functions for public API, if B is A, then it must have a public member test.
You shouldn't implement A if you don't want test() to be available as public member:
class B(val a: A) {
fun anotherMethod() = a.test("hi")
}

How do I cast custom MutableLiveData to custom LiveData?

suppose there are 2 classes:
class MyLiveData:LiveData<Int>()
class MyMutableLiveData:MutableLiveData<Int>()
Casting from MutableLiveData to LiveData is permitted:
val ld1=MutableLiveData<Int>()
val ld2:LiveData<Int> = ld1 //ok
But you can't cast your own implementations this way:
val mutable=MyMutableLiveData()
val immutable:MyLiveData = mutable //type missmatch
I understand that MutableLiveData extends LiveData thats why they are castable.But I can't have MyMutableLiveData extending MyLiveData as it won't be mutable in this case
Are there any workarounds?
UPD:I guess I need to show motivation of extending LiveData.I'm trying to implement MutableLiveDataCollection which notifies not just value changes via setValue/postValue but also value modification like adding new elements.I'm surprised there is no native solution for this.
Anyway to obseve modify events there have to be additional observe method.And this method have to be inside immutable part aka LiveDataCollection because views will call it.Inheritance is natural solution here IMHO.
The key idea sits in the MutableLiveData class.The only thing this class does - is it changes access modifiers on setValue/postValue methods.I can do the same trick.Therefore the final code will be:
open class LiveDataCollection<K,
L:MutableCollection<K>,
M:Collection<K>>: LiveData<L>() {
private var active=false
private var diffObservers = ArrayList<Observer<M>>()
fun observe(owner: LifecycleOwner, valueObserver: Observer<L>, diffObserver: Observer<M>) {
super.observe(owner,valueObserver)
diffObservers.add(diffObserver)
}
protected open fun addItems(toAdd:M) {
value?.addAll(toAdd)
if (active)
for (observer in diffObservers)
observer.onChanged(toAdd)
}
override fun removeObservers(owner: LifecycleOwner) {
super.removeObservers(owner)
diffObservers= ArrayList()
}
override fun onActive() {
super.onActive()
active=true
}
override fun onInactive() {
super.onInactive()
active=false
}
}
class MutableLiveDataCollection<K,L:MutableCollection<K>,
M:Collection<K>>: LiveDataCollection<K,L,M>() {
public override fun addItems(toAdd:M) {
super.addItems(toAdd)
}
public override fun postValue(value: L) {
super.postValue(value)
}
public override fun setValue(value: L) {
super.setValue(value)
}
}

smart class to val property inside the class

public val properties for interface does't do smart casting to the object that were set into them.
is there an alternative?
There is an option do declare 2 variables. one public interface and one private instance. but I prefer just one
what I wish to have:
class MyClass{
val myObservable: Observable<Unit> = PublishSubject.create<Unit>()
fun foo(){
myObservable.onNext(Unit) // smart casting doesn't work
}
}
what works but involves boilerplate code
class MyClass{
private val myPublisher = PublishSubject.create<Unit>()
val myObservable: Observable<Unit> = myPublisher
fun foo(){
myPublisher.onNext(Unit)
}
}

Kotlin lazy initialization in subclass

I'm trying to build a string with properties that are initialized in a subclass.
I read about lazy initialization but somehow this doesn't work as I expected.
abstract class SubProcessFullNameBuilder(technicalDomain: TechnicalDomainEnumeration) {
protected val moduleName = "td.${technicalDomain.value().toLowerCase()}.shared"
private val packageName by lazy { packageName() }
private val processName by lazy { processName() }
val processFullName: String = "$moduleName/$packageName.$processName"
protected abstract fun packageName(): String
protected abstract fun processName(): String
}
class WorkerFullNameBuilder(
private val jmsDirection: JmsDirectionEnumeration,
technicalDomain: TechnicalDomainEnumeration,
private val cdmCode: String) : SubProcessFullNameBuilder(technicalDomain) {
override fun packageName() = "$moduleName.workers.${jmsDirection.value().toLowerCase()}.${cdmCode.toLowerCase()}"
override fun processName() = "Worker"
}
Since I have overridden the packageName() and processName() properties, I would expect that on calling the packageName property it would use the implementation from the subclass.
But when I call the processFullName property, it throws a java.lang.NullPointerException.
val builder = WorkerFullNameBuilder(JmsDirectionEnumeration.ESB_IN, TechnicalDomainEnumeration.INFOR, "ccmd")
val name = builder.processFullName
How can I initialize the packageName and processName properties in a proper way?
This is a case of calling a non-final method in a constructor and thus accessing uninitialized variables.
This line is still evaluated eagerly, at the time when the base class is constructed:
val processFullName: String = "$moduleName/$packageName.$processName"
To get the values of the two lazy properties, this will make calls to the abstract methods, of which packageName() refers to jmsDirection and cdmCode to return its value - these properties are not initialized yet, because their values are set after the superclass constructor runs. Here's a simplified version of the subclass' constructor, decompiled back to Java:
public WorkerFullNameBuilder(#NotNull JmsDirectionEnumeration jmsDirection, #NotNull TechnicalDomainEnumeration technicalDomain, #NotNull String cdmCode) {
super(technicalDomain);
this.jmsDirection = jmsDirection;
this.cdmCode = cdmCode;
}
As a demonstration, if you don't refer to these, for example, if you return constants in both of the subclass methods, your code will actually run fine:
override fun packageName() = "foo"
override fun processName() = "Worker"
However, the solution you need here is most likely to make the processFullName property itself lazy instead of the two values it uses (which you're evaluating at constructor time right now anyway, so you're not making use of them being lazy). This means you don't even need those two as separate properties:
abstract class SubProcessFullNameBuilder(technicalDomain: TechnicalDomainEnumeration) {
protected val moduleName = "td.${technicalDomain.value().toLowerCase()}.shared"
val processFullName by lazy { "$moduleName/${packageName()}.${processName()}" }
protected abstract fun packageName(): String
protected abstract fun processName(): String
}

How to overcome "same JVM signature" error when implementing a Java interface?

With the code below, I am getting the following error in IntelliJ IDEA 13.1.6 and Kotlin plugin 0.11.91.AndroidStudio.3:
Platform declaration clash: The following declarations have the same JVM signature (getName()Ljava/lang/String;):
• public open fun getName(): kotlin.String?
• internal final fun <get-name>(): kotlin.String?
Java class, JavaInterface.java:
public interface JavaInterface {
public String getName();
}
Kotlin class, KotlinClass.kt
public class KotlinClass(val name: String?) : JavaInterface
I've tried overriding the 'getter' method by
adding override fun getName(): String? = name, but that produces the same error.
I can see one workaround by doing this instead:
public class KotlinClass(val namePrivate: String?) : JavaInterface {
override fun getName(): String? = namePrivate
}
But in my real-world case I have a number of properties to implement and need setters too. Doing this for each property doesn't seem very Kotlin-ish. What am I missing?
Making that variable private solves the problem.
public class KotlinClass(private val name: String?) : JavaInterface
You could use #JvmField for instructs the compiler not generate getter/setter, and you can implement your setters and getters. With this your code work well in Java (as attribute getter/setter) and Kotlin as property
Example:
JAVA:
public interface Identifiable<ID extends Serializable>
{
ID getId();
}
KOTLIN:
class IdentifiableImpl(#JvmField var id: String) :Identifiable<String>
{
override fun getId(): String
{
TODO("not implemented")
}
}
The annotation feature of Kotlin named #JvmName will solve the duplication problem in Java and Kotlin when having the same signature.
fun function(p: String) {
// ...
}
// Signature: function(Ljava/lang/String)
With the use of JvmName will be:
#JvmName("functionOfKotlin")
fun function(p: String) {
// ...
}
// Signature: functionOfKotlin(Ljava/lang/String)
IMHO most readable combination is field + explicit interface implementation by the single-expression function (combination of #Renato Garcia's and #Steven Spungin's answers):
Java:
public inteface SomeInterface {
String getFoo();
}
Kotlin:
class Implementation(#JvmField val foo: String) : SomeInterface {
override fun getFoo() = foo
}
Another work-around is to declare the properties in an abstract Kotlin class, then write a small java class that extends KotlinClass and implements JavaInterface.
// JavaInterface.java
public interface JavaInterface {
int getFoo();
void setFoo(int value);
}
// KotlinClass.kt
abstract class KotlinClass(open var foo : Int = 0) {
}
// JavaAdapter.java
class JavaAdapter extends KotlinClass implements JavaInterface {
// all code in KotlinClass, but can't implement JavaInterface there
// because kotlin properties cannot override java methods.
}
We have found that to use the same names without clashing, the ctor args must be private AND you must still override the interfaces methods. You don't need any additional backing fields. Also, your expression body assignment will not recurse, so you can safely use that syntax.
Java Interface
interface IUser {
String getUserScope();
String getUserId();
}
Kotlin Class
class SampleUser(private val userScope: String, private val userId: String) : IUser {
override fun getUserId() = userId
override fun getUserScope() = userScope
}
If you have direct control over the interface then the best approach is to write the interface in Kotlin. You can then write your class
public class KotlinClass(override val name: String?) : KotlinInterface
and still reference it from any Java code using the same interface as before. This looks a lot neater than setting all the properties to private and overriding the get function. Obviously if you can't migrate the interface to Java because you don't own it then that seems to be the only solution.
public interface JavaInterface {
public String getName();
}
public class KotlinClass(val namePrivate: String?) : JavaInterface {
private var name = namePrivate
override fun getName(): String? {
return name
}
}
Rename the variable to something else, or make it private if u dont want it to be public.
convert function to property instead of initializing property from a function.
for ex:
fun getCountriesList(): List<Country> {
val countries = mutableListOf<Country>()
countries.add(Country("in", "+91", "India", R.drawable.indian_flag))
countries.add(Country("us", "+1", "United States",R.drawable.us_flag))
return countries
}
to
val countriesList: List<Country>
get() {
val countries = mutableListOf<Country>()
countries.add(Country("in", "+91", "India", R.drawable.indian_flag))
countries.add(Country("us", "+1", "United States", R.drawable.us_flag))
return countries
}