Search code examples
androidconvertersretrofitrobospice

Configure Converter for RetrofitSpiceService


I'm using Retrofit 2.0 and Robospice libraries, included in gradle file like this:

compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
compile 'com.octo.android.robospice:robospice-retrofit:1.4.14'

I want to use the RetrofitGsonSpiceService but when I run the application I get a Suppressed: java.lang.ClassNotFoundException: retrofit.converter.GsonConverter

It's caused by the

@Override
    protected Converter createConverter() {
        return  new GsonConverter(new Gson());
    }

method of the RetrofitGsonSpiceService class.

In Retrofit 2.0 the default Converter is now excluded.

My question is do you know a simple way of configuring Robospice to easily work with Retrofit 2.0, or is out there a preconfigured SpiceService to work with the new Retrofit 2.0?


Solution

  • Not so simple as before...

    PS. I used Moshi parser, but with GSON it should be similar.

    1. You should extend SpiceService:

      public class SpiceNetworkService extends SpiceService {
      
      private Map<Class<?>, Object> retrofitInterfaceToServiceMap = new HashMap<>();
      protected List<Class<?>> retrofitInterfaceList = new ArrayList<>();
      
      @Override
      public void onCreate() {
          super.onCreate();
          addRetrofitInterface(WallpapersApi.class);
      }
      
      @SuppressWarnings("unchecked")
      protected <T> T getRetrofitService(Class<T> serviceClass) {
          T service = (T) retrofitInterfaceToServiceMap.get(serviceClass);
          if (service == null) {
              Retrofit retrofit = new Retrofit.Builder()
                      .baseUrl(getServerUrl())
                      .addConverterFactory(MoshiConverterFactory.create())
                      .build();
              service = retrofit.create(serviceClass);
              retrofitInterfaceToServiceMap.put(serviceClass, service);
          }
          return service;
      }
      
      @SuppressWarnings({"rawtypes", "unchecked"})
      @Override
      public void addRequest(CachedSpiceRequest<?> request, Set<RequestListener<?>> listRequestListener) {
          if (request.getSpiceRequest() instanceof RetrofitSpiceRequest) {
              RetrofitSpiceRequest retrofitSpiceRequest = (RetrofitSpiceRequest) request.getSpiceRequest();
              retrofitSpiceRequest.setService(getRetrofitService(retrofitSpiceRequest.getRetrofitedInterfaceClass()));
          }
          super.addRequest(request, listRequestListener);
      }
      
      public final List<Class<?>> getRetrofitInterfaceList() {
          return retrofitInterfaceList;
      }
      
      protected void addRetrofitInterface(Class<?> serviceClass) {
          retrofitInterfaceList.add(serviceClass);
      }
      
      @Override
      public CacheManager createCacheManager(Application application) throws CacheCreationException {
          CacheManager cacheManager = new CacheManager();
          cacheManager.addPersister(new MoshiPersisterFactory(application, getCacheFolder()));
          return cacheManager;
      }
      
      protected String getServerUrl() {
          return SpiceWallpapersRequest.API_URL;
      }
      
      public File getCacheFolder() {
          return null;
      }
      

      }

    2. Implement Persister factory like this:

      public class MoshiPersisterFactory extends InFileObjectPersisterFactory {
      public MoshiPersisterFactory(Application application) throws CacheCreationException {
          super(application);
      }
      
      public MoshiPersisterFactory(Application application, File cacheFolder) throws CacheCreationException {
          super(application, cacheFolder);
      }
      
      public MoshiPersisterFactory(Application application, List<Class<?>> listHandledClasses) throws CacheCreationException {
          super(application, listHandledClasses);
      }
      
      public MoshiPersisterFactory(Application application, List<Class<?>> listHandledClasses, File cacheFolder) throws CacheCreationException {
          super(application, listHandledClasses, cacheFolder);
      }
      
      @Override
      public <T> InFileObjectPersister<T> createInFileObjectPersister(Class<T> clazz, File cacheFolder) throws CacheCreationException {
          return new MoshiPersister<>(getApplication(), clazz, cacheFolder);
      }
      

      }

    3. Finally extend InFileObjectPersister:

      public class MoshiPersister extends InFileObjectPersister { public MoshiPersister(Application application, Class clazz) throws CacheCreationException { super(application, clazz); }

      public MoshiPersister(Application application, Class<T> clazz, File cacheFolder) throws CacheCreationException {
          super(application, clazz, cacheFolder);
      }
      
      @Override
      protected T readCacheDataFromFile(File file) throws CacheLoadingException {
          BufferedSource sink = null;
      
          try {
              InputStream fileInputStream = new FileInputStream(file);
              sink = Okio.buffer(Okio.source(fileInputStream));
      
              Moshi moshi = new Moshi.Builder().build();
              JsonAdapter<T> jsonAdapter = moshi.adapter(getHandledClass());
      
      
              return jsonAdapter.fromJson(sink);
          } catch (FileNotFoundException e) {
              // Should not occur (we test before if file exists)
              // Do not throw, file is not cached
              Ln.w("file " + file.getAbsolutePath() + " does not exists", e);
              return null;
          } catch (Exception e) {
              throw new CacheLoadingException(e);
          } finally {
              try {
                  if (sink != null) {
                      sink.close();
                  }
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      }
      
      @Override
      public T saveDataToCacheAndReturnData(final T data, final Object cacheKey) throws CacheSavingException {
          try {
              if (isAsyncSaveEnabled()) {
                  Thread t = new Thread() {
                      @Override
                      public void run() {
                          try {
                              saveData(data, cacheKey);
                          } catch (IOException | CacheSavingException e) {
                              Ln.w("An error occured on saving request " + cacheKey + " data asynchronously");
                          }
                      }
                  };
                  t.start();
              } else {
                  saveData(data, cacheKey);
              }
          } catch (CacheSavingException e) {
              throw e;
          } catch (Exception e) {
              throw new CacheSavingException(e);
          }
          return data;
      }
      
      private void saveData(T data, Object cacheKey) throws IOException, CacheSavingException {
          Moshi moshi = new Moshi.Builder().build();
          JsonAdapter<T> jsonAdapter = moshi.adapter(getHandledClass());
          BufferedSink sink = new Buffer();
          jsonAdapter.toJson(sink, data);
      
          FileOutputStream out = null;
          try {
              out = new FileOutputStream(getCacheFile(cacheKey));
              sink.buffer().copyTo(out);
          } finally {
              if (out != null) {
                  out.close();
              }
          }
      }
      

      }