android lock main thread after obfuscating app - multithreading

I created my app and the app is working correctly in debug mode.after obfuscating a part of application that get codes list and shows in recyclerview not working properly
in this fragment I am going to get the codes list-codes is my parcelable models class-but the main thread lock and nothing works
I tried to prevent obfuscate this class but it still does not work correctly.
I cant debug my released app to find the problem
please help me to find problem or debug the released apk
this is my codes:
the codes model class:
class Codes(
#SerializedName("id")
var id: String?,
#SerializedName("title")
var title: String?,
#SerializedName("text")
var text: String?,
#SerializedName("codes")
var codes: String?,
#SerializedName("date")
var date: String?,
#SerializedName("codeId")
var codeId: String?,
#SerializedName("point")
var point: Int,
#SerializedName("name")
var name: String?,
#SerializedName("family")
var family: String?,
#SerializedName("image")
var image: String?,
#SerializedName("jensiat")
var jensiat: Int
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readInt(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readInt()
) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(id)
parcel.writeString(title)
parcel.writeString(text)
parcel.writeString(codes)
parcel.writeString(date)
parcel.writeString(codeId)
parcel.writeInt(point)
parcel.writeString(name)
parcel.writeString(family)
parcel.writeString(image)
parcel.writeInt(jensiat)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Codes> {
override fun createFromParcel(parcel: Parcel): Codes {
return Codes(parcel)
}
override fun newArray(size: Int): Array<Codes?> {
return arrayOfNulls(size)
}
}
}
codes fragment(where I get the List and show in recyclerview):
viewModel.getAllCodes(SORT_POPULAR).observe(this, Observer {
myList = it
Utils.customAnimation(recycler, animation = Techniques.Landing)
codeAdapter = CodeAdapter(context!!, it) { codeId, position ->
Log.i("LOG","code id:$codeId and position is: $position")
var transaction = activity!!.supportFragmentManager.beginTransaction()
lastPosition = position
var detailCodeFragment = DetailCodeFragment {
codeAdapter.changePoint(it)
}
var selectedCode: Codes? = null
for (i in 0 until myList.size) {
var id = myList[i].codeId
if (id == codeId) {
selectedCode = myList[i]
}
}
var bundle = Bundle()
bundle.putParcelable("codes", selectedCode)
bundle.putInt("position", lastPosition)
detailCodeFragment.arguments = bundle
Utils.customAnimation(
activity!!.findViewById(R.id.main_fragment_frame),
animation = Techniques.SlideInRight
)
transaction.add(R.id.main_fragment_frame, detailCodeFragment)
transaction.addToBackStack(null)
transaction.commit()
}
recycler.adapter = codeAdapter
loadingFragme.visibility = View.GONE
})
}
proguard rules:
-keepattributes Signature
# For using GSON #Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-keep class sun.misc.Unsafe { *; }
#-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }
##---------------End: proguard configuration for Gson ----------
-keepclassmembers class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-keepclassmembers class * implements android.os.Parcelable {
public static final <fields>;
}

Related

When using Retrofit I get the error Cannot call adapter

I want to pull crypto data with the retrofit library using the view model and live data functions, but I am getting the following error, I would be very grateful if you could help.
The part that builds the retrofit structure :
object RetrofitInstance {
private val retrofit by lazy {
Retrofit.Builder()
.baseUrl ( BASE_URL )
.addConverterFactory ( GsonConverterFactory.create() )
.build()
}
val api: ApiTerminal by lazy {
retrofit.create ( ApiTerminal::class.java )
}
}
Interface part in this project :
interface ApiTerminal {
#GET("currencies/ticker")
suspend fun getPost ( #Query("key") key : String ): Response<ArrayList<CoinModel>>
}
The repository part in this project :
class Repository {
suspend fun getPost( key : String ) : Response<ArrayList<CoinModel>> {
return RetrofitInstance.api.getPost ( key )
}
}
The part in the project where the view model function is determined :
class MainViewModel ( private val repository: Repository ) : ViewModel() {
val response = MutableLiveData<Response<ArrayList<CoinModel>>>()
fun getPost ( key : String ) {
viewModelScope.launch {
response.value = repository.getPost ( key )
}
}
}
This part of the project is the activity area :
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val viewModelFactory = MainViewModelFactory ( Repository() )
val txt = findViewById<TextView>(R.id.txt)
txt.setOnClickListener {
val viewModel = ViewModelProvider(this, viewModelFactory )[MainViewModel::class.java]
viewModel.getPost("this part contains api key")
viewModel.response.observe(this, Observer {
if (it.isSuccessful) {
txt.text = it.body()?.get(0)?.currency
}
})
}
}
}
The error I got :
2022-04-24 22:01:28.638 5834-5834/com.rk.quex E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.rk.quex, PID: 5834
java.lang.IllegalArgumentException: Unable to create call adapter for class java.lang.Object
for method ApiTerminal.getPost
at retrofit2.ServiceMethod$Builder.methodError(ServiceMethod.java:752)
at retrofit2.ServiceMethod$Builder.createCallAdapter(ServiceMethod.java:237)
at retrofit2.ServiceMethod$Builder.build(ServiceMethod.java:162)
at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:170)
at retrofit2.Retrofit$1.invoke(Retrofit.java:147)
at java.lang.reflect.Proxy.invoke(Proxy.java:1006)
at $Proxy1.getPost(Unknown Source)
at com.rk.quex.repository.Repository.getPost(Repository.kt:11)
at com.rk.quex.MainViewModel$getPost$1.invokeSuspend(MainViewModel.kt:19)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:367)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:30)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:25)
at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:110)
at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
at kotlinx.coroutines.BuildersKt.launch(Unknown Source:1)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:47)
at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source:1)
at com.rk.quex.MainViewModel.getPost(MainViewModel.kt:17)
at com.rk.quex.MainActivity.onCreate$lambda-1(MainActivity.kt:24)
at com.rk.quex.MainActivity.$r8$lambda$hFYFqoAo62q-drAqh-AGqF7aib8(Unknown Source:0)
at com.rk.quex.MainActivity$$ExternalSyntheticLambda0.onClick(Unknown Source:6)
at android.view.View.performClick(View.java:7448)
at android.view.View.performClickInternal(View.java:7425)
at android.view.View.access$3600(View.java:810)
at android.view.View$PerformClick.run(View.java:28305)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: java.lang.IllegalArgumentException: Could not locate call adapter for class java.lang.Object.
Tried:
* retrofit2.ExecutorCallAdapterFactory
at retrofit2.Retrofit.nextCallAdapter(Retrofit.java:241)
at retrofit2.Retrofit.callAdapter(Retrofit.java:205)
at retrofit2.ServiceMethod$Builder.createCallAdapter(ServiceMethod.java:235)
... 32 more
Can you please try the following:
Please share which Retrofit version dependencies you are using.
Launch the getPost Coroutine in the IO thread:
viewModelScope.launch(Dispatchers.IO) {
//code
}
Please try to parse the body in the Repository, to get closer to MVVM principles, the ideal would be to create an event response sealed class, to be able to animate the UI depending on the Response, but I won't confuse you and I will make 2 examples, one without the event response and one with:
class Repository {
suspend fun getPost( key : String ) : ArrayList<CoinModel>? {
val response = RetrofitInstance.api.getPost(key)
return if(response.isSuccessful){
response.body?.let { arrayList ->
arrayList
} ?: run {
null
}
} else {
null
}
}
}
Example with event response sealed class:
sealed class Result <out T> {
data class Error <T> (val message: Exception?): Result<T>()
data class Success <T> (val data: T): Result<T>()
}
class Repository {
suspend fun getPost(key: String): Result<List<CoinModel>> {
return try {
val response = RetrofitInstance.api.getPost(key)
if (response.isSuccessful){
response.body()?.let { coinModelList ->
return#let Result.Success(coinModelList)
} ?: run {
Result.Error(Exception("The body is empty"))
}
} else {
Result.Error(Exception("Response not successful"))
}
} catch (e: Exception) {
Result.Error(Exception("Network error"))
}
}
}
This is how it would be from your viewModel:
class MainViewModel ( private val repository: Repository ) : ViewModel() {
val response = MutableLiveData<List<CoinModel>>()
fun getPost ( key : String ) {
viewModelScope.launch(Dispatchers.IO) {
when(val result = repository.getPost ( key )){
is Result.Error -> //Handle your error logic. You can access the Exception message with result.message
is Result.Success -> response.postValue(result.data)
}
}
}
}
Please keep in mind I wrote it "on-hand". I hope it helps :D

I face this error java.lang.IllegalArgumentException: Could not locate call adapter for class java.lang.Object

I am new with MVVM in kotlin, I want to fetch some data using retrofit and show this in textview but I can't fetch this. In this app first time, I am using the android jetpack component. I tried a lot of times but I can't solve this error. My code in below
MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val repository = Repository()
val viewModelFactory = MainViewModelFactory(repository)
viewModel = ViewModelProvider(this, viewModelFactory).get(MainViewModel::class.java)
viewModel.getEmployeeData()
viewModel.repoResponse.observe(this, Observer { response ->
if (response.isSuccessful) {
Log.d("Response", response.body()?.employee_id.toString())
Log.d("Response", response.body()?.employee_name.toString())
Log.d("Response", response.body()?.employee_age.toString())
Log.d("Response", response.body()?.employee_salary.toString())
name.text = response.body()?.employee_name!!
} else {
Log.d("Response", response.errorBody().toString())
name.text = response.code().toString()
}
})
}
MainViewModelFactory.kt
class MainViewModelFactory(private val repository: Repository):ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return MainViewModel(repository) as T
}
MainViewModel.kt
class MainViewModel(private val repository: Repository):ViewModel() {
val repoResponse:MutableLiveData<Response<Employee>> = MutableLiveData()
fun getEmployeeData(){
viewModelScope.launch {
val response = repository.getEmployeeData()
repoResponse.value = response
}
}
ApiClient.kt
object ApiClient {
private val retrofit by lazy{
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
val api:Api by lazy {
retrofit.create(Api::class.java)
}
Api.kt
public interface Api {
#GET("api/v1/employee/1")
suspend fun getEmployeeData():Response<Employee>
}
Repository.kt
class Repository {
suspend fun getEmployeeData():Response<Employee>{
return ApiClient.api.getEmployeeData()
}
Employee.kt
data class Employee(
#SerializedName("id")
var employee_id: Int,
#SerializedName("employee_name")
var employee_name: String,
#SerializedName("employee_age")
var employee_age: Int,
#SerializedName("employee_salary")
var employee_salary: Int
)
Constants.kt
class Constants {
companion object{
const val BASE_URL = "http://dummy.restapiexample.com"
}
Error image
How can i solve this? please help me. Thank you
Retrofit only supports suspend keyword since 2.6.4, so using 2.3.0 won't work.
You should update to a newer version of Retrofit. The current latest version at the time of writing is 2.9.0.

RecyclerView(Kotlin): Adding an swipe to delete functionality on a ToDo app with data in SQL database

I am new to kotlin and android studio and currently I am trying to build an todo list applications with my own ideas. Its mostly done but I have to add edit and delete functionality to the tasks that user adds. The tasks that user adds are stored on the device using SQLiteDatabase. This is the base swipe to delete class that I wrote:
abstract class SwipeToDelete(context: Context, dragDir: Int, swipeDir: Int): ItemTouchHelper.SimpleCallback(dragDir, swipeDir) {
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
return false
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
TODO("Not yet implemented")
}
}
This is the delete functionality that I have added which works great with a button:
fun deleteToDo(todoId: Long){
val db = writableDatabase
db.delete(TABLE_TODO_ITEM,"$COL_TODO_ID=?", arrayOf(todoId.toString()))
db.delete(TABLE_TODO,"$COL_ID=?", arrayOf(todoId.toString()))
}
This is the recyclerview adapter that I am using:
class ItemAdapter(val context: Context,val dbHandler: DBHandler, val list: MutableList<ToDoItem>) :
RecyclerView.Adapter<ItemAdapter.ViewHolder>(){
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(context).inflate(R.layout.rv_child_item,p0,false))
}
override fun onBindViewHolder(holder: ViewHolder, p1: Int) {
holder.itemName.text = list[p1].itemName
holder.itemName.isChecked = list[p1].isCompleted
holder.itemName.setOnClickListener{
list[p1].isCompleted = !list[p1].isCompleted
dbHandler.updateToDoItem(list[p1])
}
}
override fun getItemCount(): Int {
return list.size
}
class ViewHolder(v : View) : RecyclerView.ViewHolder(v){
val itemName : CheckBox = v.findViewById(R.id.cb_item)
}
}
but for some reason I cannot make it work when I try to call the delete function in this Swipetodelete object:
val item = object : SwipeToDelete(this,0,ItemTouchHelper.LEFT){
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
}
}
I also want to add the edit functionality but if i can get this delete functionality to work i can add it.
Since the SwipeToDelete is an abstract class, you can override the onSwiped function on your Fragment/Activity Class.
You can modify your SwipeToDelete class to:
abstract class SwipeToDelete(context: Context, dragDir: Int, swipeDir: Int): ItemTouchHelper.SimpleCallback(dragDir, swipeDir) {
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
return false
}
}
And then override the onSwiped function inside your fragment/activity and attach it to your recyclerview:
val item = object : SwipeToDelete(this,0,ItemTouchHelper.LEFT){
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
deleteToDo(todoId)
}
}
ItemTouchHelper(item).attachToRecyclerView(recycler)

How to define a protocol to include a property with #Published property wrapper

When using #Published property wrapper following current SwiftUI syntax, it seems very hard to define a protocol that includes a property with #Published, or I definitely need help :)
As I'm implementing dependency injection between a View and it's ViewModel, I need to define a ViewModelProtocol so to inject mock data to preview easily.
This is what I first tried,
protocol PersonViewModelProtocol {
#Published var person: Person
}
I get "Property 'person' declared inside a protocol cannot have a wrapper".
Then I tried this,
protocol PersonViewModelProtocol {
var $person: Published
}
Obviously didn't work because '$' is reserved.
I'm hoping a way to put a protocol between View and it's ViewModel and also leveraging the elegant #Published syntax. Thanks a lot.
You have to be explicit and describe all synthetized properties:
protocol WelcomeViewModel {
var person: Person { get }
var personPublished: Published<Person> { get }
var personPublisher: Published<Person>.Publisher { get }
}
class ViewModel: ObservableObject {
#Published var person: Person = Person()
var personPublished: Published<Person> { _person }
var personPublisher: Published<Person>.Publisher { $person }
}
My MVVM approach:
// MARK: View
struct ContentView<ViewModel: ContentViewModel>: View {
#ObservedObject var viewModel: ViewModel
var body: some View {
VStack {
Text(viewModel.name)
TextField("", text: $viewModel.name)
.border(Color.black)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(viewModel: ContentViewModelMock())
}
}
// MARK: View model
protocol ContentViewModel: ObservableObject {
var name: String { get set }
}
final class ContentViewModelImpl: ContentViewModel {
#Published var name = ""
}
final class ContentViewModelMock: ContentViewModel {
var name: String = "Test"
}
How it works:
ViewModel protocol inherits ObservableObject, so View will subscribe to ViewModel changes
property name has getter and setter, so we can use it as Binding
when View changes name property (via TextField) then View is notified about changes via #Published property in ViewModel (and UI is updated)
create View with either real implementation or mock depending on your needs
Possible downside: View has to be generic.
A workaround my coworker came up with is to use a base class that declares the property wrappers, then inherit it in the protocol. It still requires inheriting it in your class that conforms to the protocol as well, but looks clean and works nicely.
class MyPublishedProperties {
#Published var publishedProperty = "Hello"
}
protocol MyProtocol: MyPublishedProperties {
func changePublishedPropertyValue(newValue: String)
}
class MyClass: MyPublishedProperties, MyProtocol {
changePublishedPropertyValue(newValue: String) {
publishedProperty = newValue
}
}
Then in implementation:
class MyViewModel {
let myClass = MyClass()
myClass.$publishedProperty.sink { string in
print(string)
}
myClass.changePublishedPropertyValue("World")
}
// prints:
// "Hello"
// "World"
This is how I suppose it should be done:
public protocol MyProtocol {
var _person: Published<Person> { get set }
}
class MyClass: MyProtocol, ObservableObject {
#Published var person: Person
public init(person: Published<Person>) {
self._person = person
}
}
Although the compiler seems to sort of like it (the "type" part at least), there is a mismatch in the property's access control between the class and the protocol (https://docs.swift.org/swift-book/LanguageGuide/AccessControl.html). I tried different combinations: private, public, internal, fileprivate. But none worked. Might be a bug? Or missing functionality?
Until 5.2 we don't have support for property wrapper. So it's necessary expose manually the publisher property.
protocol PersonViewModelProtocol {
var personPublisher: Published<Person>.Publisher { get }
}
class ConcretePersonViewModelProtocol: PersonViewModelProtocol {
#Published private var person: Person
// Exposing manually the person publisher
var personPublisher: Published<Person>.Publisher { $person }
init(person: Person) {
self.person = person
}
func changePersonName(name: String) {
person.name = name
}
}
final class PersonDetailViewController: UIViewController {
private let viewModel = ConcretePersonViewModelProtocol(person: Person(name: "Joao da Silva", age: 60))
private var cancellables: Set<AnyCancellable> = []
func bind() {
viewModel.personPublisher
.receive(on: DispatchQueue.main)
.sink { person in
print(person.name)
}
.store(in: &cancellables)
viewModel.changePersonName(name: "Joao dos Santos")
}
}
We've encountered this as well. As of Catalina beta7, there doesn't seem to be any workaround, so our solution is to add in a conformance via an extension like so:
struct IntView : View {
#Binding var intValue: Int
var body: some View {
Stepper("My Int!", value: $intValue)
}
}
protocol IntBindingContainer {
var intValue$: Binding<Int> { get }
}
extension IntView : IntBindingContainer {
var intValue$: Binding<Int> { $intValue }
}
While this is a bit of extra ceremony, we can then add in functionality to all the IntBindingContainer implementations like so:
extension IntBindingContainer {
/// Reset the contained integer to zero
func resetToZero() {
intValue$.wrappedValue = 0
}
}
I came up with a fairly clean workaround by creating a generic ObservableValue class that you can include in your protocols.
I am unsure if there are any major drawbacks to this, but it allows me to easily create mock/injectable implementations of my protocol while still allowing use of published properties.
import Combine
class ObservableValue<T> {
#Published var value: T
init(_ value: T) {
self.value = value
}
}
protocol MyProtocol {
var name: ObservableValue<String> { get }
var age: ObservableValue<Int> { get }
}
class MyImplementation: MyProtocol {
var name: ObservableValue<String> = .init("bob")
var age: ObservableValue<Int> = .init(29)
}
class MyViewModel {
let myThing: MyProtocol = MyImplementation()
func doSomething() {
let myCancellable = myThing.age.$value
.receive(on: DispatchQueue.main)
.sink { val in
print(val)
}
}
}
Try this
import Combine
import SwiftUI
// MARK: - View Model
final class MyViewModel: ObservableObject {
#Published private(set) var value: Int = 0
func increment() {
value += 1
}
}
extension MyViewModel: MyViewViewModel { }
// MARK: - View
protocol MyViewViewModel: ObservableObject {
var value: Int { get }
func increment()
}
struct MyView<ViewModel: MyViewViewModel>: View {
#ObservedObject var viewModel: ViewModel
var body: some View {
VStack {
Text("\(viewModel.value)")
Button("Increment") {
self.viewModel.increment()
}
}
}
}
I succeeded in just requiring the plain variable, and by adding the #Published in the fulfilling class:
final class CustomListModel: IsSelectionListModel, ObservableObject {
#Published var list: [IsSelectionListEntry]
init() {
self.list = []
}
...
protocol IsSelectionListModel {
var list: [IsSelectionListEntry] { get }
...

No signature of method: is applicable for argument types error in Groovy

I am quite new to groovy and getting following error when running the below method. I am trying to pass xml file name and Map
RD.groovy
Given(~'^input currency "([^"]*)"$') { String baseCurr ->
fromCurr = baseCurr
}
When(~'^insert end Currency "([^"]*)"$') { String tragetCurr ->
toCurr = tragetCurr
}
Then(~'^get the expected end currency value "([^"]*)"$') { String result ->
assert result == currCon(fromCurr, toCurr)
}
private currCon(fromCurr, toCurr)
{
def binding = ["fromCurr": fromCurr, "toCurr": toCurr]
response = Consumer.currConvert("request/CurrencyConvert.xml",binding) --> This is line 119
assert 200 == response.status
return response.data.ConversionRateResult.toString()
}
ClassA.groovy
package abc.api.member
import abc.util.Log
import abc.util.TemplateUtil
import groovyx.net.http.ContentType
import abc.api.RestClient
class ClassA extends ClassB{
ClassA(RestClient restClient) {
super(restClient)
}
def currConvert(String xmlFilename, Map binding) {
return currencyConvertRequest(TemplateUtil.xmlFromTemplate(xmlFilename, binding))
}
def currencyConvertRequest(xmlString) {
def params = [path : 'CurrencyConvertor.asmx',
headers: globeHeaders(),
body: xmlString]
return restClient.post(params)
}
Consumer.Groovy
package abc.api.member
import geb.Browser
import org.apache.http.client.utils.URIBuilder
import abc.api.RestClient
import abc.browser.member.Admin
class Consumer {
Browser browser
String token
String userId
#Delegate
private ClassA classA
Consumer(url) {
browser = new Browser()
browser.baseUrl = baseUrl(url)
restClient = new RestClient(url)
classA = new ClassA(restClient)
}
private baseUrl(url) {
URI uri = URI.create(url)
URIBuilder builder = new URIBuilder()
URI result =builder.setHost(uri.host). //
setPath(uri.path). //
setPort(uri.port). //
setScheme(uri.scheme).
setUserInfo("Cons", "pbiCons").build()
return result.toURL().toString()
}
Error:
groovy.lang.MissingMethodException: No signature of method: abc.api.consumer.Consumer.currConvert() is applicable for argument types: (org.codehaus.groovy.runtime.GStringImpl, java.util.LinkedHashMap) values: [request/globe/CurrencyConvert.xml, [fromCurr:AUD, ...]]
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:55)
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:51)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
at RD.currCon(RD.groovy:119)
After searching the issue it turned out its a common issue. Couldn't figure out though. Because all solutions are subjective.
Just curious where I am doing wrong
Thanks
currConvert is an instance method, but it's being called as if it was a static method.
I had a similar problem like this :
class Example {
static void main (String [] args) {
printMessage(obj)
}
def printMessage(obj) {
}
}
I was getting the same exception at printMessage(obj).
It got fixed after changing it to like this :
class Example {
static void main (String [] args) {
new Example().printMessage(obj)
}
def printMessage(obj) {
}
}

Resources