I have an inner class inside a buid.gradle:
class MyClass {
MyClass(String path) {
project.project(path);
}
}
That is failing, because it cannot find project. Is there any workaround for this?
Related
I am using dagger2 2.16 version for dependency injection inside mine android project. I examine a lot of examples, and although I do not have a similar approach I get the error of "circular dependency".
Mine source code;
AppComponent.kt
#Singleton
#Component(
modules = [
AndroidSupportInjectionModule::class,
AppModule::class,
ActivityBuilderModule::class]
)
interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
fun application(application: Application): Builder
fun build(): AppComponent
}
fun inject(app: App)
}
App.kt
class App : Application(), HasActivityInjector {
#Inject
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>
override fun onCreate() {
super.onCreate()
AppInjector.init(this)
initOneSignal()
}
private fun initOneSignal() = OneSignal.startInit(this).setNotificationOpenedHandler(CustomNotificationOpenedHandler()).inFocusDisplaying(OneSignal.OSInFocusDisplayOption.Notification).init()
override fun activityInjector() = dispatchingAndroidInjector
}
ActivityBuilderModule.kt
#Module
abstract class ActivityBuilderModule {
#ContributesAndroidInjector
abstract fun contributeSplashActivity(): SplashActivity
}
AppModule.kt
#Module(includes = [(ViewModelModule::class)])
class AppModule {
#Singleton
#Provides
fun provideContext(app: Application): Context = app.applicationContext;
#Singleton
#Provides
fun provideApiService(client: OkHttpClient): ApiService {
return Retrofit.Builder()
.baseUrl(Constants.baseUrl)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
.create(ApiService::class.java)
}
#Singleton
#Provides
fun provideOkHttpClient(interceptor: HttpLoggingInterceptor): OkHttpClient {
return OkHttpClient.Builder().addInterceptor(interceptor).build()
}
#Singleton
#Provides
fun provideHttpLoggingInterceptor(): HttpLoggingInterceptor {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
return interceptor
}
}
If I remove the ActivityBuilderModule from the AppComponent, the project is compiled without problems. But if you add to the modules section, the project gives the error below.
error: [ComponentProcessor:MiscError]
dagger.internal.codegen.ComponentProcessor was unable to process this
interface because not all of its dependencies could be resolved. Check
for compilation errors or a circular dependency with generated code.
Please help me.
In App.kt you need to initialize component with the application context. the line
AppInjector.init(this)
should be inside the Activity i.e. splashActivity in which you're going to inject the dependencies.
The above mentioned error message might also appear, because kotlin stdlib is not declared as dependency. So adding e.g. implementation("org.jetbrains.kotlin:kotlin-stdlib:1.3.60") in your build.gradle(.kts) file might also help.
I want to access a member of the MainFragment class from PersonAdapter class but none of them are available. I tried making both the classes and the members public and private also but so far nothing worked.
I guess I'm missing something obvious but I just can't figure it out.
class MainFragment : Fragment() {
lateinit var personAdapter: PersonAdapter
lateinit var personListener: OnPersonSelected
private var realm: Realm by Delegates.notNull()
lateinit var realmListener: RealmChangeListener<Realm>
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val v = inflater.inflate(R.layout.fragment_main, container, false)
return v
}
class PersonAdapter() : RecyclerView.Adapter<ViewHolder>() {
var localPersonList = personList
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindItems(localPersonList[position])
holder.itemView.setOnClickListener {
Toast.makeText(context, "click", Toast.LENGTH_SHORT).show()
//I want to reach personListener from here
}
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent!!.context).inflate(R.layout.person_list_item, parent, false)
return ViewHolder(v)
}
}}
In Kotlin, nested classes cannot access the outer class instance by default, just like nested static classes can't in Java.
To do that, add the inner modifier to the nested class:
class MainFragment : Fragment() {
// ...
inner class PersonAdapter() : RecyclerView.Adapter<ViewHolder>() {
// ...
}
}
Note that an inner class holds a reference to its containing class instance, which may affect the lifetime of the latter and potentially lead to a memory leak if the inner class instance is stored globally.
See: Nested classes in the language reference
In Kotlin, there are 2 types of the nested classes.
Nested Class
inner Class
Nested class are not allowed to access the member of the outer class.
If you want to access the member of outer class in the nested class then you need to define that nested class as inner class.
class OuterClass{
var name="john"
inner class InnerClass{
//....
}
}
Add inner
Note that Android Studio's Code completion(IntelliSense) doesn't work right inside the inner class
class OuterClass {
val outerVariable = "Hello, World!"
inner class InnerClass {
// Code completion doesn't work here
val innerVariable = outerVariable // Code completion work
fun innerFunction() {
// Code completion work
}
}
}
Unable to find property: 'registerform.agencyName.Required' for component: [class=com.brazil.clasadm.application.AppnRegister$AppnRegisterForm].
My scenario is like:
public class AppnRegister extends someotherClass {
public AppnRegister() {
add(new AppnRegisterForm("registerform"));
}
class AppnRegisterForm extends Form {
TextField agencyName= null;
agencyName = new TextField("agencyName", new PropertyModel(cac, "agencyName"));
agencyName .getLocalizer().getString("registerform.agencyName.Required", this);
}
}
I tried by adding the resource bundle by the names of AppnRegisterForm.properties, AppnRegister$AppnRegisterForm.properties and all in the same place of where the AppnRegister.java is present. But I unable to clear this issue. Any suggestions on this issue?
What is AppnRegister ? It must be a Wicket MarkupContainer but there is no extends ... in your code!
The inner class should be static to be able to reach it with AppnRegister$AppnRegisterForm.
Solutions:
use AppnRegister.properties
use wicket-package.properties
Both should be next to AppnRegister.class in the classpath.
There are three classes.
// in external library, which I don't want to modify
class ComponentBase {
// I want calling this to be disallowed
forceUpdate() {}
}
class ComponentBase_MyVersion extends ComponentBase {
// I want subclasses to always call this, instead of forceUpdate()
Update() {}
}
class MyComponent extends ComponentBase_MyVersion {
DoSomething() {
// I want this to be disallowed
this.forceUpdate();
// forcing the subclass to call this instead
this.Update();
}
}
How can I accomplish this, with changes only to ComponentBase_MyVersion?
Is there a way to "hide" a base-class member?
Or perhaps a way to override the definition -- like with the "new" keyword in C# -- letting me mangle the method definition to at least make warnings appear when attempting to call it?
The OOP does not allow you to do this kind of method cancellation. You can impleement this funcion on your class with an Exception like you suggested, or use a composition: https://en.wikipedia.org/wiki/Composition_over_inheritance
Example 1:
class ComponentBase {
forceUpdate() {}
}
class ComponentBase_MyVersion extends ComponentBase {
Update() {}
forceUpdate() {
throw new Error("Do not call this. Call Update() instead.");
}
}
class MyComponent extends ComponentBase_MyVersion {
DoSomething() {
// wil raise an exception
this.forceUpdate();
this.Update();
}
}
Example 2 (composition):
class ComponentBase {
forceUpdate() {}
}
class ComponentBase_MyVersion {
private _component: ComponentBase = ...;
Update() {}
// expose _component desired members ...
}
class MyComponent extends ComponentBase_MyVersion {
DoSomething() {
// compilation error
this.forceUpdate();
this.Update();
}
}
I hope I helped.
Encapsulate implementation by replacing inheritance with composition Delegation Pattern
You can do this by adding the private access modifier on the forceUpdate method. This will result in all the subclasses being unable to access forceUpdate. However TypeScript does not support package access modifiers, but you can do this by replacing inheritance with composition.
class ComponentBase {
forceUpdate() {
}
}
class ComponentBase_MyVersion {
// Replace inheritance with composition.
private component: ComponentBase;
Update() {
this.component.forceUpdate();
}
}
class MyComponent extends ComponentBase_MyVersion {
DoSomething() {
// Now subclass can't access forceUpdate method
this.Update();
}
}
Use a symbol in order to prevent external access to the method.
If you don't want to replace inheritance with composition, you can use Symbol to define a method. If your target is es5 you must configure tsconfig.json compilerOptions.lib to include es2015.symbol. Because every symbol is unique, any external module will not be able to obtain the symbol and access the method.
// libs.ts
let forceUpdate = Symbol("forceUpdate");
export class ComponentBase {
[forceUpdate]() {
}
}
export default class ComponentBase_MyVersion extends ComponentBase {
Update() {
this[forceUpdate]();
}
}
// test.ts
import ComponentBase_MyVersion from "./libs";
class MyComponent extends ComponentBase_MyVersion {
DoSomething() {
// Now subclass can't access the forceUpdate method.
this.Update();
}
}
I found a way that seems to work -- that is, which causes warnings to appear when someone attempts to call forceUpdate() on a subclass instance.
forceUpdate(_: ()=>"Do not call this. Call Update() instead.") {
throw new Error("Do not call this. Call Update() instead.");
}
Now when I write new MyComponent().forceUpdate(), I get a compiler error, with the warning message containing a description telling me to use Update() instead.
EDIT: Apparently this only works because the base class already had this definition:
forceUpdate(callBack?: () => any): void;
If instead the base method is defined with no arguments originally (as in the OP), the above solution doesn't work.
However, if you have a case like mine (where there's an optional property like that, which you can narrow the return-type of), it works fine. (not sure if this return-type-narrowing is a bug, or intended)
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.google.guava:guava:18.0'
}
}
apply plugin: LolPlugin
class LolPlugin implements Plugin<Project> {
public void apply(Project p) {
p.buildscript.dependencies.each {
println it
}
}
}
In this example, you can try to get dependencies name inside custom plugin class.
But it's different between contents of output and the expected .
I expect that,
'com.google.guava:guava:18.0'
But output is
org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependenciesHandler_Decorate#174b0a8
Almost duplicate of this question: How to iterate gradle dependencies in custom gradle plugin?
Short answer:
class LolPlugin implements Plugin<Project> {
public void apply(Project p) {
p.buildscript.configurations.each {
it.allDependencies.each {
println "${it.group}:${it.name}:${it.version}"
}
}
}
}