java.net.ProtocolException: unexpected end of stream (implementation 'com.squareup.okhttp3:okhttp:4.2.0') - okhttp

I am getting this exception:
java.net.ProtocolException: unexpected end of stream W/System.err: at okhttp3.internal.http1.Http1ExchangeCodec$FixedLengthSource.read(Http1ExchangeCodec.kt:392)
I am trying to do SOAP Request. I'm not always getting this exception. Sometimes I get the right answer from the web server.
I changed the parser library from SimpleXML to TikXML but that I am still getting the same problem. At the onResponse method I am not doing anything but I had the same the problem.
Here is how I make the call:
final Call<ResponseEnvelope> consumeWS = RetrofitGenerator
.getConsultarTipoDeDocumentoApi()
.getTiposDeDocumento(this.USERNAME_ENCRYPT, this.USERTOKEN_ENCRYPT,
this.MESSAGEID_ENCRYPT, "close", this.requestEnvelope);
consumeWS.enqueue(new Callback<ResponseEnvelope>() {
#Override
public void onResponse(Call<ResponseEnvelope> call, Response<ResponseEnvelope> response) {
ResponseEnvelope responseEnvelope = new ResponseEnvelope(response.body().getBody());
if(responseEnvelope != null && response.isSuccessful())
dataTipoDeDocumento.setValue(responseEnvelope.getBody().getMtrtipdoccResponse()
.getReturn().getLISTAREGISTROS().getLIST());
}
#Override
public void onFailure(Call<ResponseEnvelope> call, Throwable t) {
t.printStackTrace();
dataTipoDeDocumento.setValue(null);
Here is my RetrofitGenerator:
private static OkHttpClient.Builder okHttpClient = new OkHttpClient
.Builder();
private static Retrofit.Builder retrofitBuilder = new Retrofit.Builder()
.addConverterFactory(SimpleXmlConverterFactory.create(serializer));
public RetrofitGenerator() {
}
public static <S> S createService(Class<S> serviceClass, String baseUrl) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.level(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = okHttpClient
.connectTimeout(5, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.addInterceptor(logging)
.build();
Retrofit retrofit = retrofitBuilder.baseUrl(baseUrl).client(client).build();
return retrofit.create(serviceClass);
}
Here is the problem: (Debugging the request)
override fun read(sink: Buffer, byteCount: Long): Long {
require(byteCount >= 0L) { "byteCount < 0: $byteCount" }
check(!closed) { "closed" }
if (bytesRemaining == 0L) return -1
val read = super.read(sink, minOf(bytesRemaining, byteCount))
if (read == -1L) {
realConnection!!.noNewExchanges() // The server didn't supply the promised content length.
val e = ProtocolException("unexpected end of stream")
responseBodyComplete()
throw e
}
I noticed that when it fails there is a variable named bytesRemaining that get the value 1 (when it fails it is always 1). The content-length of the response is always 933. I don't know what is happening.
Here is my gradle:
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.app.multired"
minSdkVersion 22
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
dataBinding {
enabled = true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
implementation 'com.google.android.material:material:1.0.0'
implementation 'com.jakewharton:butterknife:10.0.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:10.0.0'
/* dagger dependency for DI*/
implementation "com.google.dagger:dagger:2.16"
annotationProcessor "com.google.dagger:dagger-compiler:2.16"
compileOnly 'javax.annotation:jsr250-api:1.0'
implementation 'javax.inject:javax.inject:1'
/*Retrofit lib*/
testImplementation 'com.squareup.okhttp3:mockwebserver:4.2.0'
implementation 'com.squareup.okhttp3:okhttp:4.2.0'
implementation 'com.squareup.retrofit2:retrofit:2.6.1'
implementation 'com.squareup.okhttp3:logging-interceptor:4.2.0'
//implementation 'com.squareup.okhttp3:okhttp:3.12.0'
implementation 'com.squareup.retrofit2:converter-simplexml:2.6.1'
/*RxJava lib*/
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation "io.reactivex.rxjava2:rxjava:2.1.8"
implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
/* LiveData lib*/
implementation "android.arch.lifecycle:extensions:1.1.1"
implementation "android.arch.lifecycle:runtime:1.1.1"
annotationProcessor "android.arch.lifecycle:compiler:1.1.1"
implementation 'androidx.recyclerview:recyclerview:1.0.0'
/* Biometric Authentication */
implementation 'androidx.biometric:biometric:1.0.0-alpha03'
implementation 'org.jetbrains:annotations:15.0'
}
How I solved it:
public abstract class CallbackWithRetry<T> implements Callback<T> {
private static final String TAG = CallbackWithRetry.class.getSimpleName();
#Override
public void onFailure(Call<T> call, Throwable t){
Log.e(TAG, t.getLocalizedMessage());
retry(call);
}
private void retry(Call<T> call){
call.clone().enqueue(this);
}
}
The edited Callback:
final Call<ConsultarTipoDeDocumentoResponseEnvelope> consumeWS = RetrofitGenerator
.getConsultarTipoDeDocumentoApi()
.getTiposDeDocumento(this.USERNAME_ENCRYPT, this.USERTOKEN_ENCRYPT,
this.MESSAGEID_ENCRYPT, this.consultarTipoDeDocumentoRequestEnvelope);
consumeWS.enqueue(new CallbackWithRetry<ConsultarTipoDeDocumentoResponseEnvelope>() {
#Override
public void onResponse(Call<ConsultarTipoDeDocumentoResponseEnvelope> call, Response<ConsultarTipoDeDocumentoResponseEnvelope> response) {
ConsultarTipoDeDocumentoResponseEnvelope consultarTipoDeDocumentoResponseEnvelope = new ConsultarTipoDeDocumentoResponseEnvelope(response.body().getBody());
if(consultarTipoDeDocumentoResponseEnvelope != null && response.isSuccessful())
dataTipoDeDocumento.setValue(consultarTipoDeDocumentoResponseEnvelope.getBody().getMtrtipdoccResponse()
.getReturn().getLISTAREGISTROS().getLIST());
}
#Override
public void onFailure(Call<ConsultarTipoDeDocumentoResponseEnvelope> call, Throwable t) {
super.onFailure(call, t);
}
});
This retry is very useful since Retrofit2 included the call variable as a parameter of the onFailure method when you do the enqueue Call.

My guess is that the server measured the response length using String.length() (or similar) but the content was not all ASCII and so the encoded length in bytes was greater.
You can confirm this by seeing if there are any non-ASCII characters in the broken responses.

Related

Spring Boot Resilience4j circuit breaker and fall back not implementing

I have a simple rest api with Resilience4j implementation but for some reason the circuit breaker or fallback implementation is not working. I am not sure If I am using right dependency. I have a simple member-info-api which consume another api called benefit-api. I have implemented the circuit breaker on benefit api call and a logic to create a timeout exception. When it is run its still wait on the timeout and then throw the TimeOutException. Look like my Circuit breaker is not being implemented. here is my code:
build.gradle
plugins {
id 'org.springframework.boot' version '2.7.2'
id 'io.spring.dependency-management' version '1.0.12.RELEASE'
id 'java'
}
group = 'com.thomsoncodes'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
repositories {
mavenCentral()
}
ext {
set('springCloudVersion', "2021.0.3")
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.cloud:spring-cloud-starter-circuitbreaker-reactor-resilience4j'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.projectreactor:reactor-test'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
tasks.named('test') {
useJUnitPlatform()
}
controller class
#RestController
public class WebController {
public static final Logger LOG = LoggerFactory.getLogger(WebController.class);
#Autowired
private MemberInfoService memberInfoService;
#GetMapping("member/{memId}")
public ResponseEntity<MemberInfo> memberInfo(#PathVariable("memId") String memId) throws TimeoutException {
LOG.info("---Beginning of the WebController.methodmemberInfo()---");
MemberInfo resp = null;
resp = memberInfoService.getMemberInfo(memId);
LOG.info("---End of the WebController.methodmemberInfo()---");
return new ResponseEntity<MemberInfo>(resp, (HttpStatus.OK));
}
}
MemberInfoService.java
#Service
public class MemberInfoService {
public static final Logger LOG = LoggerFactory.getLogger(MemberInfoService.class);
#Autowired
private UserInfoService userInfoService;
#Autowired
private BenefitService benefitService;
public MemberInfo getMemberInfo(String memId) throws TimeoutException {
LOG.info("---End of the WebController.MemberInfoService()---");
MemberInfo memberInfo = null;
memberInfo = userInfoService.getUserInfo(memId);
Benefit benefit = null;
benefit = benefitService.getBenefitInfo(memId);
memberInfo.setBenefit(benefit);
LOG.info("---End of the WebController.MemberInfoService()---");
return memberInfo;
}
}
BenefitService.java
#Service
public class BenefitService {
public static final Logger LOG = LoggerFactory.getLogger(BenefitService.class);
#Autowired
private WebClient benefitApiClient;
#CircuitBreaker(name = "benefitService", fallbackMethod = "buildFallbackBenefitInfo")
#RateLimiter(name = "benefitService", fallbackMethod = "buildFallbackBenefitInfo")
#Retry(name = "retryBenefitService", fallbackMethod = "buildFallbackBenefitInfo")
public Benefit getBenefitInfo(String memId) throws TimeoutException {
LOG.info("---Beginning of the BenefitService.getBenefitInfo()---");
randomlyRunLong();
return benefitApiClient.get()
.uri("/member/benefit/" + memId)
.retrieve()
.bodyToMono(Benefit.class)
.block();
}
public Benefit buildFallbackBenefitInfo(String memId, Throwable t) throws TimeoutException {
Benefit benefit = null;
benefit = new Benefit();
benefit.setBenefitId("00000");
benefit.setMemeberId("00000");
return benefit;
}
private void randomlyRunLong() throws TimeoutException{
Random rand = new Random();
int randomNum = rand.nextInt((3 - 1) + 1) + 1;
if (randomNum==3) sleep();
}
private void sleep() throws TimeoutException{
try {
System.out.println("Sleep");
Thread.sleep(5000);
throw new java.util.concurrent.TimeoutException();
} catch (InterruptedException e) {
LOG.error(e.getMessage());
}
}
}
application.yml
server:
port: 9095
management.endpoints.enabled-by-default: false
management.endpoint.health:
enabled: true
show-details: always
resilience4j.circuitbreaker:
instances:
benefitService:
registerHealthIndicator: true
ringBufferSizeInClosedState: 5
ringBufferSizeInHalfOpenState: 3
waitDurationInOpenState: 10s
failureRateThreshold: 50
recordExceptions:
- org.springframework.web.client.HttpServerErrorException
- java.io.IOException
- java.util.concurrent.TimeoutException
- org.springframework.web.client.ResourceAccessException
resilience4j.ratelimiter:
instances:
benefitService:
limitForPeriod: 5
limitRefreshPeriod: 5000
timeoutDuration: 1000ms
resilience4j.retry:
instances:
retryBenefitService:
maxRetryAttempts: 5
waitDuration: 10000
retry-exceptions:
- java.util.concurrent.TimeoutException
resilience4j.bulkhead:
instances:
bulkheadBenefitService:
maxWaitDuration: 2ms
maxConcurrentCalls: 20
resilience4j.thread-pool-bulkhead:
instances:
bulkheadBenefitService:
maxThreadPoolSize: 1
coreThreadPoolSize: 1
queueCapacity: 1
I am not sure what wrong I am doing here. A help would be really appreciated. Thanks in advance
The default Resilience4j aspect order is
Retry( CircuitBreaker( RateLimiter( TimeLimiter( Bulkhead( function)))))
Your RateLimiter has a fallback, so it never throws an exception, so CircuitBreaker never sees a failed invocation. Specify a fallback on only the last aspect that will execute.

Trouble with Resilience4j Retry and "java.net.http.HttpClient" working together

I'm trying to get a basic "httpclient" "httprequest" "httpresponse" working with Resilience4j Retry.
The verbatim code from : https://resilience4j.readme.io/docs/retry
RetryConfig config = RetryConfig.custom()
.maxAttempts(5)
.waitDuration(Duration.ofMillis(1000))
.retryOnResult(response -> response.getStatus() == 500)
.retryOnException(e -> e instanceof WebServiceException)
.retryExceptions(IOException.class, TimeoutException.class)
.ignoreExceptions(BusinessException.class, OtherBusinessException.class)
.build();
// Create a RetryRegistry with a custom global configuration
RetryRegistry registry = RetryRegistry.of(config);
// Get or create a Retry from the registry -
// Retry will be backed by the default config
Retry retryWithDefaultConfig = registry.retry("name1");
Note, their code above misses defining the generic "T", like this:
RetryConfig config = RetryConfig.<MyConcrete>custom()
and the verbatim code from : https://resilience4j.readme.io/docs/examples
Supplier<String> supplierWithResultAndExceptionHandler = SupplierUtils
.andThen(supplier, (result, exception) -> "Hello Recovery");
Supplier<HttpResponse> supplier = () -> httpClient.doRemoteCall();
Supplier<HttpResponse> supplierWithResultHandling = SupplierUtils.andThen(supplier, result -> {
if (result.getStatusCode() == 400) {
throw new ClientException();
} else if (result.getStatusCode() == 500) {
throw new ServerException();
}
return result;
});
HttpResponse httpResponse = circuitBreaker
.executeSupplier(supplierWithResultHandling);
======
So using those 2 "partials" , I've come up with this.
Note, I am using some "real" java.net.http.HttpClient and java.net.http.HttpResponse (from JDK11)
import io.github.resilience4j.core.SupplierUtils;
import io.github.resilience4j.retry.Retry;
import io.github.resilience4j.retry.RetryConfig;
import io.github.resilience4j.retry.RetryRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import javax.inject.Inject;
import java.io.IOException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.concurrent.TimeoutException;
import java.util.function.Supplier;
public final class ResilientHttpClient /* implements IResilientHttpClient */ {
private static Logger logger;
private final HttpClient httpClient;
#Inject
public ResilientHttpClient(final HttpClient httpClient) {
this(LoggerFactory
.getLogger(ResilientHttpClient.class), httpClient);
}
/**
* Constructor, which pre-populates the provider with one resource instance.
*/
public ResilientHttpClient(final Logger lgr,
final HttpClient httpClient) {
if (null == lgr) {
throw new IllegalArgumentException("Logger is null");
}
this.logger = lgr;
if (null == httpClient) {
throw new IllegalArgumentException("HttpClient is null");
}
this.httpClient = httpClient;
}
public String executeHttpRequest(String circuitbreakerInstanceName, HttpRequest httpRequest) {
try {
/* circuitbreakerInstanceName is future place holder for .yml configuration see : https://resilience4j.readme.io/docs/getting-started-3 */
RetryConfig config = RetryConfig.<HttpResponse>custom()
.waitDuration(Duration.ofMillis(1000))
.retryOnResult(response -> response.statusCode() == 500)
.retryOnException(e -> e instanceof ArithmeticException)
.retryExceptions(IOException.class, TimeoutException.class)
//.ignoreExceptions(BusinessException.class, OtherBusinessException.class)
.build();
// Create a RetryRegistry with a custom global configuration
RetryRegistry registry = RetryRegistry.of(config);
// Get or create a Retry from the registry -
// Retry will be backed by the default config
Retry retryWithDefaultConfig = registry.retry(circuitbreakerInstanceName);
Supplier<HttpResponse> supplier = () -> this.httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
Supplier<String> supplierWithResultAndExceptionHandler = SupplierUtils
.andThen(supplier, (result, exception) -> "Hello Recovery");
Supplier<HttpResponse> supplierWithResultHandling = SupplierUtils.andThen(supplier, result -> {
if (result.statusCode() == HttpStatus.BAD_REQUEST.value()) {
throw new RuntimeException("400");
} else if (result.statusCode() == HttpStatus.INTERNAL_SERVER_ERROR.value()) {
throw new RuntimeException("500");
}
return result;
});
HttpResponse<String> response = retryWithDefaultConfig.executeSupplier(supplierWithResultHandling);
String responseBody = response.body();
return responseBody;
} catch (Exception ex) {
throw new RuntimeException((ex));
}
}
}
The issue I am having is:
The line:
Supplier<HttpResponse> supplier = () - > this.httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
is giving an error (in intelliJ) of "unhandled exceptions" "IOException, InterruptedException"
So modifying the method to be:
public String executeHttpRequest(String circuitbreakerInstanceName, HttpRequest httpRequest) throws IOException, InterruptedException {
"feels wrong". But even when I try it...it doesn't resolve anything. :(
It is probably some lamda checked-exception voodoo.
But more to the point:
So I don't know if the way I've brought together the 2 partials is even correct. The samples are a little lacking in the fully-working area.
Thank for any help. Getting a basic httpclient "retry" a few times shouldn't be too hard. But I'm hitting my head against the wall.
My gradle dependencies.
dependencies {
implementation group: 'javax.inject', name: 'javax.inject', version: javaxInjectVersion
implementation group: 'org.slf4j', name: 'slf4j-api', version: slf4jVersion
implementation group: 'org.springframework', name: 'spring-web', version: springWebVersion
implementation "io.github.resilience4j:resilience4j-circuitbreaker:${resilience4jVersion}"
implementation "io.github.resilience4j:resilience4j-ratelimiter:${resilience4jVersion}"
implementation "io.github.resilience4j:resilience4j-retry:${resilience4jVersion}"
implementation "io.github.resilience4j:resilience4j-bulkhead:${resilience4jVersion}"
implementation "io.github.resilience4j:resilience4j-cache:${resilience4jVersion}"
implementation "io.github.resilience4j:resilience4j-timelimiter:${resilience4jVersion}"
testCompile group: 'junit', name: 'junit', version: junitVersion
}
and
resilience4jVersion = '1.5.0'
slf4jVersion = "1.7.30"
javaxInjectVersion = "1"
springWebVersion = '5.2.8.RELEASE'
junitVersion = "4.12"
just out of interest:
Which Java version are you using? Java 11?
Why can't you use Spring Boot? The Resilience4j Spring Boot starter simplifies the configuration a lot.
If you configure retryOnResult(response -> response.getStatus() == 500), you don't have to use SupplierUtils anymore to map a HttpResponse with a certain status code to a runtime exception.
RetryConfig config = RetryConfig.<HttpResponse<String>>custom()
.waitDuration(Duration.ofMillis(1000))
.retryOnResult(response -> response.statusCode() == 500)
.retryExceptions(IOException.class, TimeoutException.class)
.build();
Please don't create Registries and Configs inside of executeHttpRequest, but inject them into your Constructor.
You can create a static method like this:
public static <T> HttpResponse<T> executeHttpRequest(Callable<HttpResponse<T>> callable, Retry retry, CircuitBreaker circuitBreaker) throws Exception {
return Decorators.ofCallable(callable)
.withRetry(retry)
.withCircuitBreaker(circuitBreaker)
.call();
}
and invoke the method as follows:
HttpResponse<String> response = executeHttpRequest(
() -> httpClient.send(request, HttpResponse.BodyHandlers.ofString()),
retry,
circuitBreaker);

Circular view path [error] while json output expected in springboot

newbie to Springboot with gradle, I am creating a restful service which queries the db2 database and returns the result in json.
The desired output
{
resource: {
results: [
{
currencyCode: "JPY",
conversionRateToUSD: "0.010286580",
conversionRateFromUSD: "97.214040040",
startDate: "2011-01-01",
endDate: "2011-01-29"
}
]
}
}
The api i am trying to build is http://localhost:8080/apis/exchange-rates/referenceDate=2015-01-01&currencyCode=JPY
I have created the below controller class
#RestController
#Slf4j
#RequestMapping("/apis")
public class IndividualExchangeRateController {
#Autowired
private IndividualExchangeRateService individualExchangeRateService;
public IndividualExchangeRateController(IndividualExchangeRateService individualExchangeRateService) {
this.individualExchangeRateService = individualExchangeRateService;
}
#RequestMapping(value = "/exchange-rates", method = RequestMethod.GET)
#ResponseStatus(HttpStatus.OK)
public #ResponseBody IndividualResource getIndividual(#RequestParam("referenceDate") #DateTimeFormat(pattern = "YYYY-MM-DD")Date referenceDate,
#RequestParam(value = "currencyCode", required = false) String currencyCode){
try {
System.out.println("Inside Controller");
return individualExchangeRateService.getIndividualExchangeRate(referenceDate, currencyCode);
}
catch (HttpClientErrorException e){
throw new InvalidRequestException(e.getMessage());
}
}
}
I am getting the below error when i call the api
javax.servlet.ServletException: Circular view path [error]: would dispatch back to the current handler URL [/error] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
Can anybody help out on this ?
As the output is json i do not have thymeleaf dependencies on my application
Below is the gradle build file
plugins {
id 'org.springframework.boot' version '2.1.7.RELEASE'
id 'java'
}
apply plugin: 'io.spring.dependency-management'
group = 'com.abc.service'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
maven { url "http://artifactory.abcinc.dev/artifactory/maven-repos" }
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
compileOnly 'org.projectlombok:lombok:1.18.8'
annotationProcessor 'org.projectlombok:lombok:1.18.8'
runtime 'com.ibm.db2.jcc:db2jcc4:4.19.49'
compile group: 'org.springframework', name: 'spring-jdbc', version: '5.1.9.RELEASE'
compile group: 'com.zaxxer', name: 'HikariCP', version: '3.3.1'
compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.9.9'
}
public class IndividualExchangeRate {
private String currencyCode;
private double conversionRateFromUSD;
private double conversionRateToUSD;
}
public class IndividualResource {
private List<IndividualExchangeRate> individualExchangeRates;
}
All the classes are annotated with lombok.
Spring Boot uses a default Whitelabel error page in case server error.So there might be some code snippets which is breaking your appliaction flow.
Add server.error.whitelabel.enabled=false in your application.properties file .
OR add the following code snippets :
#Controller
public class AppErrorController implements ErrorController{
private static final String PATH = "/error";
#RequestMapping(value = PATH)
public String error() {
return "Error handling";
}
#Override
public String getErrorPath() {
return PATH;
}
}

error: cannot find symbol import com.google.firebase.iid.InstanceIdResult after migrating to AndroidX

I had a flutter app working fine, then I thought I'd upgrade all my plugins to androidX, and everything work fine before I decided to add firebase_messaging, I've tried version 4,5, none worked, keep throwing that error as if i'm on the wrong version. And I also tried flutter packages pub cache repair no luck. there's many issues related on github, however they all got closed with people still complaining the fix is not working.
here's my gradle looks like
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '3'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0.1'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
apply plugin: 'com.google.gms.google-services'
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
compileSdkVersion 28
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.sggo.uni"
minSdkVersion 21
targetSdkVersion 28
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// ndk {
// abiFilters 'x86', 'armeabi-v7a'
// }
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
flutter {
source '../..'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
}
buildscript {
ext.kotlin_version = '1.3.31'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.google.gms:google-services:4.0.2'
}
}
allprojects {
configurations.all {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
def requested = details.requested
if (requested.group == 'com.google.firebase') {
details.useVersion "15.+"
}
}
}
repositories {
google()
jcenter()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}
import com.google.firebase.iid.InstanceIdResult;
^
symbol: class InstanceIdResult
location: package com.google.firebase.iid
/Users/test/Desktop/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-5.0.0/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java:106: error: cannot find symbol
new OnCompleteListener() {
^
symbol: class InstanceIdResult
location: class FirebaseMessagingPlugin
/Users/test/Desktop/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-5.0.0/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java:108: error: cannot find symbol
public void onComplete(#NonNull Task task) {
^
symbol: class InstanceIdResult
/Users/test/Desktop/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-5.0.0/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java:104: error: cannot find symbol
.getInstanceId()
^
symbol: method getInstanceId()
location: class FirebaseInstanceId
/Users/test/Desktop/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-5.0.0/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java:133: error: cannot find symbol
new OnCompleteListener() {
^
symbol: class InstanceIdResult
location: class FirebaseMessagingPlugin
/Users/test/Desktop/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-5.0.0/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java:135: error: cannot find symbol
public void onComplete(#NonNull Task task) {
^
symbol: class InstanceIdResult
/Users/test/Desktop/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-5.0.0/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java:131: error: cannot find symbol
.getInstanceId()
^
symbol: method getInstanceId()
location: class FirebaseInstanceId
/Users/test/Desktop/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-5.0.0/android/src/main/java/io/flutter/plugins/firebasemessaging/FlutterFirebaseMessagingService.java:39: error: method does not override or implement a method from a supertype
#Override
Yes, because com.google.firebase.iid.InstanceIdResult is deprecated and no longer available.
Thus in order to get token from firebase now you have to use.
FirebaseMessaging.getInstance().getToken()
.addOnCompleteListener(new OnCompleteListener<String>() {
#Override
public void onComplete(#NonNull Task<String> task) {
if (!task.isSuccessful()) {
Log.w(TAG, "Fetching FCM registration token failed", task.getException());
return;
}
// Get new FCM registration token
String token = task.getResult();
// Log and toast
String msg = getString(R.string.msg_token_fmt, token);
Log.d(TAG, msg);
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
}
});
below change solved my problem
from :
ext {
firebaseMessagingVersion = "+" // default: "+"
}
to:
ext {
firebaseMessagingVersion = "21.1.0"
}
I was able to fix the issue by using this exactbuild gradle and google-services version number combo, hope it some how helps you
buildscript {
ext.kotlin_version = '1.3.31'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.google.gms:google-services:4.2.0'
}
}
allprojects {
repositories {
google()
jcenter()
}
}

Error 406 on Spring 3+Google App Engine on Android Studio

I am using Google App Engine to develop a backend module provided by Android Studio. I am also using Spring 3 to map URL to class.Although,I have successfully used the combo on Eclipse.But on Android Studio getting a peculiar error(May be because of gradle error).Consider the following files-
build.gradle
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.google.appengine:gradle-appengine-plugin:1.9.18'
}
}
repositories {
jcenter();
}
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'appengine'
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
dependencies {
appengineSdk 'com.google.appengine:appengine-java-sdk:1.9.18'
compile 'javax.servlet:servlet-api:2.5'
compile 'org.springframework:spring-webmvc:4.0.0.RELEASE'
compile 'com.google.code.gson:gson:2.5'
}
appengine {
downloadSdk = true
appcfg {
oauth2 = true
}
}
MyServlet.java . When I am accessing conventional MyServlet the Gson get successfully loaded and returns the required JSON.
public class MyServlet extends HttpServlet {
#Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("application/json");
Gson gson = new Gson();
Shop sh = new Shop();
sh.setName("Gufran Kurshid");
sh.setAddress("Pitampura new Delhi");
sh.setId(5235);
resp.getWriter().println(gson.toJson(sh));
}
}
MyController.java - A normal controller URL /hello is also easily accessible.But /getDummyJSON which is made to return JSON is giving Error 406.
#Controller
#RequestMapping("/greet")
public class MyController {
#RequestMapping("/hello")
public ModelAndView helloDost() {
ModelAndView modelAndView = new ModelAndView("rat");
modelAndView.addObject("message", "Hello Dost");
return modelAndView;
}
#RequestMapping(value = "/getDummyJSON", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
public
#ResponseBody
Map getDummyJSON() {
Map map = new HashMap<String, Object>();
map.put("status", true);
map.put("message", "Hello Friends");
return map;
}
}
My study says the Spring is not able map and load Gson classes.Is there any thing wrong with Android Studio or my Gradle file ?

Resources