Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
6bb80d6
kotlin: encapsulate the logic to check internal nested type in function
pwrobeldev Jan 28, 2026
319b75c
kotlin: simplify 'resolveName()' method of visibility resolver
pwrobeldev Jan 28, 2026
6dcbe5e
kotlin: ensure that elements nested in internals are also explicitly …
pwrobeldev Jan 28, 2026
a51bf11
smoke-tests: showcase nested internal elements
pwrobeldev Feb 19, 2026
2ce3d43
functional-tests: remove java interoperability cases that fail to com…
pwrobeldev Feb 19, 2026
e8f16cf
kotlin: remove unused 'isInternal' predicate
pwrobeldev Jan 28, 2026
9b40a40
kotlin: encapsulate the logic for conceptually internal types
pwrobeldev Jan 28, 2026
3d30c6c
kotlin: remove unused functions from visibility resolver
pwrobeldev Feb 19, 2026
7ee642a
kotlin: resolve JvmSynthetic via synthetic resolver
pwrobeldev Jan 28, 2026
3764b6d
smoke tests: show usage of JvmSynthetic for functions in interfaces
pwrobeldev Feb 19, 2026
1530ebc
functional-tests: remove java interoperability cases that fail to com…
pwrobeldev Feb 19, 2026
3692816
smoke-tests: show missing jvm synthetic for properties in interface
pwrobeldev Feb 19, 2026
f459cef
kotlin: annotate properties in internal interfaces as synthetic
pwrobeldev Jan 28, 2026
76d8843
smoke-tests: showcase jvm synthetic for properties in internal interf…
pwrobeldev Feb 19, 2026
cceb7ac
functional-tests: use internal interface in Kotlin test
pwrobeldev Feb 19, 2026
f3440b6
Adjust CHANGELOG.md
pwrobeldev Feb 19, 2026
341364c
functional-tests: remove outdated tests that do not use internal fields
pwrobeldev Feb 19, 2026
52e1433
smoke-tests: elements nested in internal class for Kotlin
pwrobeldev Feb 22, 2026
9c64eab
functional-tests: elements nested in internal class for Kotlin
pwrobeldev Feb 22, 2026
c901939
Kotlin: add missing JvmSynthetic for exception's field
pwrobeldev Feb 22, 2026
e95b5bc
smoke-tests: generate synthetic annotation for kotlin exceptions
pwrobeldev Feb 22, 2026
03a08c6
functional-tests: do not trigger compilation error in Java/Kotlin int…
pwrobeldev Feb 22, 2026
1384afe
Adjust CHANGELOG.md
pwrobeldev Feb 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
# Gluecodium project Release Notes

## Unreleased
* Kotlin: explicitly generate 'internal' visibility and synthetic attribute for elements nested in 'internal' type.

## 14.1.0
Release date 2026-02-21
* Kotlin: use `@JvmSynthetic` annotation for Kotlin internal elements whenever possible to hide them from Java code.
* Kotlin: ensure that visibility of each element nested in another internal element is explicitly set via 'internal' Kotlin keyword.
* Kotlin: allow the usage of 'RequiresOptIn' and 'OptIn' annotations for internal API via CLI parameters. This way error is generated when the code, which is not intended to access the internal API uses it. Three new CLI parameters are available: 'androidrequiresoptinannotation', 'androidoptinannotation' and 'androidinternalapiannotationname'.
* Kotlin: for external types usage in Kotlin, use 'internal' keyword for the types, which are generated by Gluecodium as their 'internal' representation.
* Kotlin: minimize the usage of 'JvmSuppressWildcards' annotation for collection parameters. This annotation was used for all generated collection types. It needs to be used only when collection type holds enumeration or open type e.g.: 'open class', 'interface' or 'fun interface'.
Expand Down
2 changes: 2 additions & 0 deletions functional-tests/functional/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -456,9 +456,11 @@ feature(Visibility android android-kotlin swift dart SOURCES
input/lime/VisibilityPlatform.lime
input/lime/VisibilityPlatformReverse.lime
input/lime/InternalFields.lime
input/lime/NestedInternalElements.lime

input/src/cpp/VisibilityAttribute.cpp
input/src/cpp/VisibilityInternal.cpp
input/src/cpp/NestedInternalElements.cpp
)

feature(SkipAttribute cpp android android-kotlin swift dart SOURCES
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
/*
* Copyright (C) 2016-2026 HERE Europe B.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* License-Filename: LICENSE
*/
@file:OptIn(com.here.android.lorem.ipsum.FunctionalTestsInternalAPI::class)

package com.here.android.test

import com.here.android.RobolectricApplication
import org.junit.Assert.assertEquals
import org.junit.Assert.assertThrows
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config

@RunWith(RobolectricTestRunner::class)
@Config(application = RobolectricApplication::class)
class NestedInternalElementsTest {
////////// 1. Tests related to direct members of 'InternalClassWithNestedElements'.
@Test
fun constantOfInternalClassCanBeAccessed() {
assertEquals(2026, InternalClassWithNestedElements.SOME_CONSTANT)
}

@Test
fun functionOfInternalClassCanBeAccessed() {
val internalClassObj = InternalClassWithNestedElements(20, 26)
assertEquals(46, internalClassObj.someFunction())
}

@Test
fun staticFunctionOfInternalClassCanBeAccessed() {
assertEquals("SOME_STATIC_FUNCTION", InternalClassWithNestedElements.someStaticFunction())
}

@Test
fun propertyOfInternalClassCanBeAccessed() {
val internalClassObj = InternalClassWithNestedElements(20, 26)
assertEquals(2202, internalClassObj.someProperty)

internalClassObj.someProperty = 77
assertEquals(77, internalClassObj.someProperty)
}

@Test
fun staticPropertyOfInternalClassCanBeAccessed() {
assertEquals(11, InternalClassWithNestedElements.getSomeStaticProperty())

InternalClassWithNestedElements.setSomeStaticProperty(37)
assertEquals(37, InternalClassWithNestedElements.getSomeStaticProperty())
}

////////// 2. Tests related to direct members of 'InternalClassWithNestedElements.NestedClassLevelOne'.
@Test
fun functionOfClassNestedInInternalClassCanBeAccessed() {
val obj = InternalClassWithNestedElements.NestedClassLevelOne(2, 3)
assertEquals(6, obj.someNestedFunction())
}

@Test
fun staticFunctionOfClassNestedInInternalClassCanBeAccessed() {
assertEquals("LEVEL_1_NESTING", InternalClassWithNestedElements.NestedClassLevelOne.someNestedStaticFunction())
}

@Test
fun propertyOfClassNestedInInternalClassCanBeAccessed() {
val obj = InternalClassWithNestedElements.NestedClassLevelOne(2, 3)
assertEquals(333, obj.someNestedProperty)

obj.someNestedProperty = 11
assertEquals(11, obj.someNestedProperty)
}

@Test
fun staticPropertyOfClassNestedInInternalClassCanBeAccessed() {
assertEquals(77, InternalClassWithNestedElements.NestedClassLevelOne.getSomeNestedStaticProperty())

InternalClassWithNestedElements.NestedClassLevelOne.setSomeNestedStaticProperty(37)
assertEquals(37, InternalClassWithNestedElements.NestedClassLevelOne.getSomeNestedStaticProperty())
}

////////// 3. Tests related to direct members of 'InternalClassWithNestedElements.NestedClassLevelOne.NestedClassLevelTwo'.
@Test
fun functionOfClassNestedInClassNestedInInternalClassCanBeAccessed() {
val obj = InternalClassWithNestedElements.NestedClassLevelOne.NestedClassLevelTwo(2, 33)
assertEquals(66, obj.doubleNestedFunction())
}

@Test
fun staticFunctionOfClassNestedInClassNestedInInternalClassCanBeAccessed() {
assertEquals("LEVEL_2_NESTING", InternalClassWithNestedElements.NestedClassLevelOne.NestedClassLevelTwo.doubleNestedStaticFunction())
}

@Test
fun propertyOfClassNestedInClassNestedInInternalClassCanBeAccessed() {
val obj = InternalClassWithNestedElements.NestedClassLevelOne.NestedClassLevelTwo(2, 33)
assertEquals(17, obj.doubleNestedProperty)

obj.doubleNestedProperty = 13
assertEquals(13, obj.doubleNestedProperty)
}

@Test
fun staticPropertyOfClassNestedInClassNestedInInternalClassCanBeAccessed() {
assertEquals(123, InternalClassWithNestedElements.NestedClassLevelOne.NestedClassLevelTwo.getDoubleNestedStaticProperty())

InternalClassWithNestedElements.NestedClassLevelOne.NestedClassLevelTwo.setDoubleNestedStaticProperty(9)
assertEquals(9, InternalClassWithNestedElements.NestedClassLevelOne.NestedClassLevelTwo.getDoubleNestedStaticProperty())
}

////////// 4. Tests related to nested enum, nested exception and nested lambda.
@Test
fun enumeratorsOfEnumNestedInInternalClassCanBeAccessed() {
val someObject = InternalClassWithNestedElements.NestedEnum.OPTION_1
assertEquals(1, someObject.value)

assertEquals(InternalClassWithNestedElements.NestedEnum.OPTION_1, someObject)
}

@Test
fun exceptionNestedInInternalClassCanBeAccessed() {
val exception = assertThrows(InternalClassWithNestedElements.NestedException::class.java) {
InternalClassWithNestedElements.throwNestedException()
}
assertEquals(exception.error, InternalClassWithNestedElements.NestedEnum.OPTION_1)
}

@Test
fun lambdaNestedInInternalClassCanBeAccessedWhenObtainedFromCpp() {
val someLambda = InternalClassWithNestedElements.produceNestedLambda()
assertEquals("CONTENT_FROM_NESTED_LAMBDA_FROM_CPP: 'Kotlin 2026'", someLambda.apply("Kotlin ", 2026))
}

////////// 5. Tests related to direct members of 'InternalClassWithNestedElements.NestedStruct'.
@Test
fun fieldsOfStructNestedInInternalClassCanBeAccessed() {
val obj = InternalClassWithNestedElements.NestedStruct(10, 2026)
assertEquals(10, obj.firstField)
assertEquals("2026", obj.secondField)
}

@Test
fun fieldConstructorOfStructNestedInInternalClassCanBeAccessed() {
val obj = InternalClassWithNestedElements.NestedStruct(123, "NESTED_STRUCT")
assertEquals(123, obj.firstField)
assertEquals("NESTED_STRUCT", obj.secondField)
}

@Test
fun functionOfStructNestedInInternalClassCanBeAccessed() {
val obj = InternalClassWithNestedElements.NestedStruct(10, 2026)
assertEquals(20, obj.nestedStructFunction())
}

@Test
fun staticFunctionOfStructNestedInInternalClassCanBeAccessed() {
assertEquals("NESTED_STRUCT_STATIC_FUN", InternalClassWithNestedElements.NestedStruct.nestedStructStaticFunction())
}

////////// 6. Tests related to direct members of 'InternalClassWithNestedElements.NestedInterface'.
@Test
fun staticFunctionOfInterfaceNestedInInternalClassCanBeAccessed() {
assertEquals("NESTED_ITF_STATIC_FUN", InternalClassWithNestedElements.NestedInterface.nestedInterfaceStaticFunction())
}

@Test
fun staticPropertyOfInterfaceNestedInInternalClassCanBeAccessed() {
assertEquals(572, InternalClassWithNestedElements.NestedInterface.getNestedInterfaceStaticProperty())

InternalClassWithNestedElements.NestedInterface.setNestedInterfaceStaticProperty(37)
assertEquals(37, InternalClassWithNestedElements.NestedInterface.getNestedInterfaceStaticProperty())
}

@Test
fun interfaceNestedInInternalClassCanBeAccessedWhenObtainedFromCpp() {
val itfImpl = InternalClassWithNestedElements.produceNestedInterfaceImplementation()
assertEquals(909, itfImpl.nestedInterfaceFunction())
assertEquals(77, itfImpl.nestedInterfaceProperty)

itfImpl.nestedInterfaceProperty = 123
assertEquals(123, itfImpl.nestedInterfaceProperty)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,22 @@ import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config

class ImplementationOfSomeInternalInterface: SomeInternalInterface {
class ImplementationOfSomeInternalInterface : SomeInternalInterface {
override fun foo(): Int = 709
override fun bar(): Long = 121
}

class ImplementationOfInternalAttributeInterfaceParent : InternalAttributeInterfaceParent {
override fun fooBar() {}
override var prop: String
get() = propHolder
set(value) {
propHolder = value
}

private var propHolder: String = "Hello world!"
}

@RunWith(RobolectricTestRunner::class)
@Config(application = RobolectricApplication::class)
class VisibilityAttributeTest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,6 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

class ImplementationOfSomeInternalInterface implements SomeInternalInterface {
@Override
public int foo() {
return 709;
}

@Override
public long bar() {
return 121;
}
}

@RunWith(RobolectricTestRunner.class)
@Config(sdk = Build.VERSION_CODES.M, application = RobolectricApplication.class)
public class VisibilityAttributeTest {
Expand All @@ -52,40 +40,11 @@ public void internalConstructorOfClassCanBeCalled() {
SomeClassWithInternalMembers someObject = new SomeClassWithInternalMembers();
}

@Test
public void functionOfInternalClassCanBeCalled() {
SomeInternalClassWithMembers someObject = SomeInternalClassWithMembers.create();
assertEquals(987, someObject.someFunction());
}

@Test
public void staticFunctionOfInternalClassCanBeCalled() {
assertEquals(765, SomeInternalClassWithMembers.someStaticFunction());
}

@Test
public void fieldOfInternalStructCanBeAccessed() {
SomeInternalStructWithMembers someObject = SomeInternalStructWithMembers.create();
assertEquals(123, someObject.someInteger);
assertEquals(456, someObject.someLong);
}

@Test
public void functionOfInternalStructCanBeCalled() {
SomeInternalStructWithMembers someObject = SomeInternalStructWithMembers.create();
assertEquals(32, someObject.someFunction());
}

@Test
public void internalFieldOfStructCanBeAccessed() {
SomeStructWithInternalMembers someObject = new SomeStructWithInternalMembers(21);
assertEquals(21, someObject.someInteger);
assertEquals(444, someObject.someLong);
}

@Test
public void internalFreeArgsCtorCanBeCalled() {
SomeStructWithInternalFreeArgsCtor someObject = new SomeStructWithInternalFreeArgsCtor(33);

// Note: 'someObject.someString' is a public field of public structure.
assertEquals("Special string", someObject.someString);
}

Expand All @@ -97,6 +56,8 @@ public void internalAllArgsCtorCanBeCalled() {
@Test
public void internalFieldCtorCanBeCalled() {
SomeStructWithInternalFieldConstructor someObject = new SomeStructWithInternalFieldConstructor(77);

// Note: 'someObject.someString' is a public field of public structure.
assertEquals("QAZWSX", someObject.someString);
}

Expand All @@ -106,18 +67,10 @@ public void valueOfInternalEnumCanBeAccessed() {
assertEquals(SomeInternalEnum.TWO, someObject);
}

@Test
public void internaInterfaceFromJavaCanBeUsed() {
ImplementationOfSomeInternalInterface someInterfaceImpl = new ImplementationOfSomeInternalInterface();
SomeStructWithInternalMembers someObject = new SomeStructWithInternalMembers(21);
}

@Test
public void internalExceptionCanBeThrown() {
SomethingBadHappenedException exception = assertThrows(SomethingBadHappenedException.class, () -> {
throw new SomethingBadHappenedException(SomeInternalEnum.ONE);
});

assertEquals(exception.error, SomeInternalEnum.ONE);
}
}
Loading