2012-02-18 3 views
16

Я пытаюсь создать простой клиент Android для веб-службы, которую я создал, но что-то не так во время выполнения.Джерси-клиент на Android - NullPointerException

Вот Клиент:

public class MyClient extends AsyncTask<EditText, Integer, String> { 

private EditText text; 

protected String doInBackground(EditText... strings) { 

    RuntimeDelegate 
      .setInstance(new com.sun.ws.rs.ext.RuntimeDelegateImpl()); 
    WebResource wbr; 
    Client client = Client.create(); 
    wbr = client 
      .resource("http://my.ip:8080/MazeService/rest/service/hello"); 
    String result = wbr.queryParam("number", "10") 
      .accept(MediaType.APPLICATION_JSON).get(String.class); 
    text = strings[0]; 
    return result; 
} 

protected void onProgressUpdate(Integer... progress) { 
    // setProgressPercent(progress[0]); 
} 

protected void onPostExecute(String result) { 
    if (result != null) 
     this.text.setText(result); 
    else 
     Log.d("MyApp", "No Result"); 
} 

}

и обслуживание:

@Path("/service") 
public class AndroidService { 

@GET 
@Produces(MediaType.APPLICATION_JSON) 
@Path("/hello") 
public String getJSON(@QueryParam("number") String nr) 
{ 

    String s = "Hi there! The number is: "+nr; 
    return s; 
} 
} 

Я получаю эту StackTrace в LogCat:

02-18 16:26:06.446: E/AndroidRuntime(1381): FATAL EXCEPTION: AsyncTask #1 
02-18 16:26:06.446: E/AndroidRuntime(1381): java.lang.RuntimeException: An error occured while executing doInBackground() 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at android.os.AsyncTask$3.done(AsyncTask.java:278) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at java.util.concurrent.FutureTask.setException(FutureTask.java:124) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at java.util.concurrent.FutureTask.run(FutureTask.java:137) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at java.lang.Thread.run(Thread.java:856) 
02-18 16:26:06.446: E/AndroidRuntime(1381): Caused by: java.lang.NullPointerException 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at javax.ws.rs.core.MediaType.valueOf(MediaType.java:119) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at com.sun.jersey.api.client.ClientResponse.getType(ClientResponse.java:615) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:532) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:506) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at com.sun.jersey.api.client.WebResource.handle(WebResource.java:674) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:503) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at com.maze.client.MyClient.doInBackground(MyClient.java:25) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at com.maze.client.MyClient.doInBackground(MyClient.java:1) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at android.os.AsyncTask$2.call(AsyncTask.java:264) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  ... 5 more 

Я не понимаю что про blem, так как аналогичный клиент работает на ПК. Нет проблем с IP-адресом, так как я могу получить доступ к серверу с Android VirtualDevice.

Версия для Android 4.0.3 версия API 15. Для клиента я использовал Jersey 1.11.

EDIT

Я также попытался удалить все это с EditText, так как кто-то сказал мне, что не используется, как это должно быть. Тем не менее, у меня такая же ошибка. Я просто не понимаю, что я делаю неправильно. Если я покажу любую другую дополнительную информацию, пожалуйста, дайте мне знать. Кроме того, ЛЮБАЯ идея хороша. Я новичок в Android, и я, возможно, допустил некоторые глупые ошибки.

+0

Ваша проблема является NullPointer что-то связано с 'String result = wbr.queryParam (« число »,« 10 ») .accept (MediaType.APPLICATION_JSON) .get (String.class);' – Blundell

+0

@Blundell Да, я думал, что это может быть проблема , но я не понимаю, почему эта проблема возникает, поскольку простая программа, содержащая этот код, отлично работает. – Dragos

+0

@ L7ColWinters Я не понимаю, как именно я должен это делать. Укажите код. – Dragos

ответ

18

предложение Павла является правильным. Я немного глубже в этом вопросе и нашел причину.

Инструмент для упаковки Android apk (класс APKBuilder из sdklib.jar) игнорирует разные папки, пока он создает пакет (source). Одна из этих папок - META-INF - независимо от того, находится ли она в прикрепленной библиотеке или в исходной папке проекта.

Обходное решение для версии 1.8 (и, возможно, другое также, но я его не тестировал), чтобы предоставить пользовательские (по умолчанию один ищет META-INF/services/который отсутствует в android apk) для ServiceFinder$ServiceIteratorProvider который имеет жестко закодированные имена классов поставщика.Я основана моя реализация на this реализации предложенной Лукаса:

import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.Iterator; 

import android.util.Log; 

import com.sun.jersey.spi.service.ServiceFinder.ServiceIteratorProvider; 

public class AndroidServiceIteratorProvider<T> extends ServiceIteratorProvider<T> { 

    private static final String TAG = AndroidServiceIteratorProvider.class.getSimpleName(); 
    private static final String MESSAGE = "Unable to load provider"; 

    private static final HashMap<String, String[]> SERVICES = new HashMap<String, String[]>(); 

    private static final String[] com_sun_jersey_spi_HeaderDelegateProvider = { 
      "com.sun.jersey.core.impl.provider.header.MediaTypeProvider", 
      "com.sun.jersey.core.impl.provider.header.StringProvider" 
    }; 

    private static final String[] com_sun_jersey_spi_inject_InjectableProvider = { 
    }; 

    private static final String[] javax_ws_rs_ext_MessageBodyReader = { 
      "com.sun.jersey.core.impl.provider.entity.StringProvider", 
      "com.sun.jersey.core.impl.provider.entity.ReaderProvider" 
    }; 

    private static final String[] javax_ws_rs_ext_MessageBodyWriter = { 
      "com.sun.jersey.core.impl.provider.entity.StringProvider", 
      "com.sun.jersey.core.impl.provider.entity.ReaderProvider" 
    }; 

    static { 
     SERVICES.put("com.sun.jersey.spi.HeaderDelegateProvider", 
       com_sun_jersey_spi_HeaderDelegateProvider); 
     SERVICES.put("com.sun.jersey.spi.inject.InjectableProvider", 
       com_sun_jersey_spi_inject_InjectableProvider); 
     SERVICES.put("javax.ws.rs.ext.MessageBodyReader", 
       javax_ws_rs_ext_MessageBodyReader); 
     SERVICES.put("javax.ws.rs.ext.MessageBodyWriter", 
       javax_ws_rs_ext_MessageBodyWriter); 
     SERVICES.put("jersey-client-components", new String[]{}); 
     SERVICES.put("com.sun.jersey.client.proxy.ViewProxyProvider", new String[]{}); 
    } 

    @SuppressWarnings("unchecked") 
    @Override 
    public Iterator<Class<T>> createClassIterator(Class<T> service, 
      String serviceName, ClassLoader loader, 
      boolean ignoreOnClassNotFound) { 

     String[] classesNames = SERVICES.get(serviceName); 
     int length = classesNames.length; 
     ArrayList<Class<T>> classes = new ArrayList<Class<T>>(length); 
     for (int i = 0; i < length; i++) { 
      try { 
       classes.add((Class<T>) Class.forName(classesNames[i])); 
      } catch (ClassNotFoundException e) { 
       Log.v(TAG, MESSAGE,e); 
      } 
     } 
     return classes.iterator(); 
    } 

    @Override 
    public Iterator<T> createIterator(Class<T> service, String serviceName, 
      ClassLoader loader, boolean ignoreOnClassNotFound) { 

     String[] classesNames = SERVICES.get(serviceName); 
     int length = classesNames.length; 
     ArrayList<T> classes = new ArrayList<T>(length); 
      for (int i = 0; i &lt; length; i++) { 
      try { 
       classes.add(service.cast(Class.forName(classesNames[i]) 
         .newInstance())); 
      } catch (IllegalAccessException e) { 
       Log.v(TAG, MESSAGE,e); 
      } catch (InstantiationException e) { 
       Log.v(TAG, MESSAGE,e); 
      } catch (ClassNotFoundException e) { 
       Log.v(TAG, MESSAGE,e); 
      } 
     } 

     return classes.iterator(); 
    } 
} 

Я удалил большинство классов, так как я их не использовал, а также они были причиной ошибки проверки на Dalvik VM ...

NOTE : Это означает, что при этой реализации вы можете использовать только подмножество заголовков/типов, поддерживаемых Джерси (мне нужна только строка). Чтобы поддерживать другие типы, вам нужно добавить поставщиков, находящихся в папке META-INF/services jersey-client.jar (или из реализации Lucas), и проверить, не вызывают ли они ошибки проверки на Android.

Приведенный выше код должен использоваться следующим образом:

ServiceFinder.setIteratorProvider(new AndroidServiceIteratorProvider()); 
Client client = Client.create(); 

EDIT:

кажется, что проблема была fixed в андроид-Maven-плагин.

МСД ... @ gmail.com писал:

запрос Тянуть с исправлением был слит в мастер и будет выпущен с 3.2.1:

1

После кода:

com/sun/jersey/api/client/ClientResponse.getType()

613 public MediaType getType() { 
614  String ct = getHeaders().getFirst("Content-Type"); 
615  return (ct != null) ? MediaType.valueOf(ct) : null; 
616 } 

Я бы проверить, что делегат, используемый MEDIATYPE не null.

javax/ws/rs/core/MediaType.valueOf(java.lang.String)

118 public static MediaType valueOf(String type) throws IllegalArgumentException { 
119  return delegate.fromString(type); 
120 } 

Похоже, возможно delegate является null для одного клиента (Android), а не null для вашего другого клиента.

Посмотрите на это, чтобы узнать, как инициализируется делегат. Это может помочь в ваших расследованиях.

javax/ws/rs/ext/RuntimeDelegate.java

+0

Спасибо, я посмотрю, с чем я смогу справиться. – Dragos

Смежные вопросы