0

In my Android application, I want to fetch the details of the user's profile using the token that is sent in the header format, but I get the following errors

Specify the JSON Parsing Error:

java.io.EOFException: End of input at line 1 column 1 path $ at com.google.gson.stream.JsonReader.nextNonWhite space(JsonReaderjaval 406) at com.google.gson.stream.JsonReader.consumeNonE xecutePrefix(JsonReaderjaval 615) at com.google.gson.stream.JsonReader.doPeek(JsonR eader.java.544) at com.google.gson.stream.JsonReader. peek(JsonRea derjava:435) at com.google.gson.internal.bind.ReflectiveTypeAdapt erFactory$Adapter.read(ReflectiveTypeAdapterFacto ry.java:251) at retrofit2.converter.gson.GsonResponseBodyConvert er.convert(GsonResponseBodyConverter.java:40) at retrofit2.convertergson.GsonResponseBodyConvert er. convert(GsonResponseBodyConverter.java:27) at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java: 243) at retrofit.2.0 kHttpCall$1.onResponse(OkHttpCall.java: 153) at okhttp3.internal.connection.RealCall$AsyncCall.run( RealCall.kt:519) at java.util.concurrent.ThreadPoolExecutor.runWorker( ThreadPoolExecutor.java:1137) at lava i itil rnnr•I irrpnt ThrparlPnnIFvpri rtnrW/nrkpr n in( 

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $ at com.google.gson.internal.bind.ReflectiveTypeAdapt erFactory$Adapter.read(ReflectiveTypeAdapterFacto ry.java:270) at retrofit2.converter.gson.GsonResponseBodyConvert erconvert(GsonResponseBodyConverterjava:40) at retrofit2.converter.gson.GsonResponseBodyConvert erconvert(GsonResponseBodyConverterjava:27) at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java: 243) at retrofit2.0kHttpCall$1.onResponse(OkHttpCall.java: 153) at okhttp3.internal.connection.RealCall$AsyncCall.run( RealCall.kt:519) at java.util.concurrent.ThreadPoolExecutor.runWorker( ThreadPoolExecutor.java:1137) at java.util.concurrent.ThreadPoolExecutor$Worker.run( ThreadPoolExecutor.java:637) at java.lang.Thread.run(Thread.javal 012) Suppressed: kotlinx.coroutines. DiagnosticCoroutineContextExcep tion: [StandaloneCoroutine{Cancelling}@acd6dc7, Dispatchers.Mainimmediate] Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $ 
at 
Network Module
@Provides
@Singleton
fun provideInterceptor() = HttpLoggingInterceptor().apply {
    level =
        if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
}

@Provides
@Singleton
fun provideClient(
    timeOut: Long,
    @Named(NAMED_PING) ping: Long,
    session: SessionManager,
    interceptor: HttpLoggingInterceptor
) = OkHttpClient.Builder()
    .addInterceptor { chain ->
        val token = runBlocking {
            session.getToken.first().toString()
        }
        chain.proceed(chain.request().newBuilder().also {
            it.addHeader(AUTHORIZATION, "$token")
            it.addHeader(ACCEPT, APPLICATION_JSON)
        }.build())

    }.also { client ->
        client.addInterceptor(interceptor)
    }
    .writeTimeout(timeOut, TimeUnit.SECONDS)
    .readTimeout(timeOut, TimeUnit.SECONDS)
    .connectTimeout(timeOut, TimeUnit.SECONDS)
    .retryOnConnectionFailure(true)
    .pingInterval(ping, TimeUnit.SECONDS)
    .build()

@Provides
@Singleton
fun provideRetrofit(baseUrl: String, gson: Gson, client: OkHttpClient): ApiServices =
    Retrofit.Builder()
        .baseUrl(baseUrl)
        .client(client)
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build()
        .create(ApiServices::class.java)

}

ApiService

    @GET("profile/show_profile.php")
    suspend fun getInfoUser(): Response<ResponseInfoUser>

ResponseInfoUser

import com.google.gson.annotations.SerializedName

data class ResponseInfoUser(
    @field:SerializedName("date")
    val date: String?, // 2023-09-02
    @field:SerializedName("email")
    val email: String?, // 
    @field:SerializedName("image")
    val image: String?, // 
    @field:SerializedName("name_family")
    val nameFamily: String? // mahdi
)

I also wrote in this way

data class ResponseInfoUser(
    @SerializedName("date")
    val date: String?, // 2023-09-02
    @SerializedName("email")
    val email: String?, // 
    @SerializedName("image")
    val image: String?, // 
    @SerializedName("name_family")
    val nameFamily: String? // mahdi
)

HomeRepository

class HomeRepository @Inject constructor(private val api: ApiServices) {
    suspend fun getInfoUser() = api.getInfoUser()
}

MviHomeIntent

sealed class HomeIntent {
    object ShowInfoUser :HomeIntent()
}

HomeState

sealed class HomeState {
    object Idle : HomeState()
    object LoadingProfile : HomeState()
    data class ShowInfoUser(val profile: ResponseInfoUser) : HomeState()
    object Empty : HomeState()
    data class Error(val error: String) : HomeState()
}

HomeViewModel

@HiltViewModel
class HomeViewModel @Inject constructor(private val repository: HomeRepository) : ViewModel() {
    //Login
    val intentChannel = Channel<HomeIntent>()
    private val _state = MutableStateFlow<HomeState>(HomeState.Idle)
    val state: StateFlow<HomeState> get() = _state

    init {
        handleIntents()
    }

    private fun handleIntents() = viewModelScope.launch {
        intentChannel.consumeAsFlow().collect { intent ->
            when (intent) {
                is HomeIntent.ShowInfoUser -> fetchingProfileUser()
            }
        }
    }


    private fun fetchingProfileUser() = viewModelScope.launch {
        val response = repository.getInfoUser()
        _state.emit(HomeState.LoadingProfile)
        when (response.code()) {
            in 200..202 -> {
                _state.emit(HomeState.ShowInfoUser(response.body()!!))
            }

            in 400..499 -> {
                _state.emit(HomeState.Error(""))
            }

            in 500..599 -> {
                _state.emit(HomeState.Error(""))
            }
        }

    }




}

BackEnd PHP

<?php
header("Access-Control-Allow-Origin: *"); 
header("Content-Type: application/json; charset=UTF-8");
if ($_SERVER['REQUEST_METHOD'] === 'POST') {

  require '../connection.php';
  
      $rawToken = $_SERVER['HTTP_AUTHORIZATION'];
      $token = preg_replace('/Bearer\s+|\[|\]/i', '', $rawToken);


     $sql="SELECT * FROM tbl_subscribers WHERE token= :token";

  $resault=$connect->prepare($sql);
  $resault->bindParam(':token', $token);
  $resault->execute();

    while($row=$resault->fetch(PDO::FETCH_ASSOC)){
        
        $record["name_family"]=$row['name_family'];
        $record["email"]=$row['email'];
        $record["date"]=$row['date'];
        $record["image"]=$row['image'];

    }
        echo JSON_encode($record);

}
?> 

call Postman Api Response

I also changed the received response for the data class, but the error was not fixed


data class ResponseInfoUser(
    @SerializedName("date")
    val date: String, // 2023-08-27
    @SerializedName("email")
    val email: String, // 
    @SerializedName("image")
    val image: String, // http
    @SerializedName("name_family")
    val nameFamily: String // dggf
)
5
  • 2
    Handle the exception and log the JSON you're getting Commented Sep 10, 2023 at 3:59
  • How should I do this? Commented Sep 10, 2023 at 11:13
  • Your error is sort of self-explanatory: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path. You expect a JSON object (i.e. {...}), but actually you receive a List of JSON objects (i.e. [...]) Commented Sep 11, 2023 at 5:12
  • Thank you. Is the error related to api? Is there no way to solve the problem in Android? Commented Sep 15, 2023 at 9:23
  • @Noah; you can solve this by either adjusting your PHP code, or the Android app code. The cause for the EOFException is probably that your PHP code produces an empty response when no matching record is found. It should either produce valid JSON (e.g. null) or send HTTP 4... to indicate an error. For Expected BEGIN_OBJECT but was BEGIN_ARRAY as jujka pointed out, the JSON structure is incorrect. Please verify that your PHP code really always responds with a JSON object { ... }. Commented Oct 6, 2023 at 20:43

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.