#Get arbitrary query parameters in Android Annotations - android

It seems that I am unable to set arbitrary query parameters to a #Get declaration
My endpoint looks like
http://api.lmiforall.org.uk/api/v1/ashe/estimateHours?soc=2349&coarse=true
There are a non trivial amount of parameters to this query, is there a declaration I can use to indicate this to the #Rest interface?
I tried declaring it as this, but it complains about fields being unused.
#Get("estimateHours")
ASHEFilterInfo GetEstimateHours( int soc, boolean coarse, String filters, String breakdown);
java: #org.androidannotations.annotations.rest.Get annotated method has only url variables in the method parameters

Look at AA cookbook.
Try this (not tested):
#Rest(rootUrl = "http://api.lmiforall.org.uk/api/v1/ashe")
public interface MyService {
#Get("/estimateHours?soc={soc}&coarse={coarse}&breakdown={breakdonw}&filters={filters}")
ASHEFilterInfo GetEstimateHoursFiltered( int soc, boolean coarse, String filters, String breakdown);
#Get("/estimateHours?soc={soc}&coarse={coarse}&breakdown={breakdonw}")
ASHEFilterInfo GetEstimateHours( int soc, boolean coarse, String breakdown);
}

When I needed to create #Get request with many dynamic parameteres, and some of them could be duplicated, I had resolved that problem so:
#Rest(rootUrl = "http://example.com:9080/",
converters = { GsonHttpMessageConverter.class },
interceptors = { ApiInterceptor.class })
public interface ExampleApi {
#Get("content/home/product-type/list?{filters}&domain={domain}") //filters is String like "param1=value1&param1=value2&param3=value3"
ProductTypeListResponse getProductTypeList(int domain, String filters);
}
public class ApiInterceptor implements ClientHttpRequestInterceptor {
private static final String TAG = ApiInterceptor.class.getSimpleName();
#Override
public ClientHttpResponse intercept(final HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
final QueryMultiParamsHttpRequest modifiedRequest = new QueryMultiParamsHttpRequest(request);
return execution.execute(modifiedRequest, body);
}
}
public class QueryMultiParamsHttpRequest implements HttpRequest {
private static final String TAG = QueryParametersBuilder.class.getSimpleName();
private HttpRequest httpRequest;
public QueryMultiParamsHttpRequest(final HttpRequest httpRequest) {
this.httpRequest = httpRequest;
}
#Override
public HttpMethod getMethod() {
return httpRequest.getMethod();
}
#Override
public URI getURI() {
final URI originalURI = httpRequest.getURI();
final String query = originalURI.getQuery() != null ? originalURI.getQuery().replace("%3D", "=").replace("%26", "&") : null;
URI newURI = null;
try {
newURI = new URI(originalURI.getScheme(), originalURI.getUserInfo(), originalURI.getHost(), originalURI.getPort(), originalURI.getPath(),
query, originalURI.getFragment());
} catch (URISyntaxException e) {
Log.e(TAG, "Error while creating URI of QueryMultiParamsHttpRequest", e);
}
return newURI;
}
#Override
public HttpHeaders getHeaders() {
return httpRequest.getHeaders();
}
}
So, I created a wrapper for HttpRequest, that can decode symbols "=" and "&". And this wrapper replaces original HttpRequest in ApiInterceptor. This is a little hacky solution, but it works.

I ran into this same issue and came up with a another solution that while far from ideal, works. The particular problem I was trying to solve was handling "HATEOAS" links.
What I ended up doing was creating a separate class called HATEOASClient to contain endpoint methods that would not escape the HATEOAS links passed in as params. To do that I basically just looked at an auto generated endpoint method and coped/tweaked the body in my implementation.
These methods use the same RestTemplate instance AndroidAnnotations sets up so you still get access to all the general setup you do on the RestTemplate.
For example:
public ResponseEntity<Foo> postFoo(Foo foo) {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set(RestHeader.AUTH_TOKEN_HEADER, getClient().getHeader(RestHeader.AUTH_TOKEN_HEADER));
httpHeaders.set(RestHeader.ACCEPT_LANGUAGE_HEADER, getClient().getHeader(RestHeader.ACCEPT_LANGUAGE_HEADER));
httpHeaders.setAuthorization(authentication);
HttpEntity<Foo> requestEntity = new HttpEntity<>(null, httpHeaders);
HashMap<String, Object> urlVariables = new HashMap<>();
urlVariables.put("link", foo.getLinks().getFooCreate().getHref());
URI expanded = new UriTemplate(getClient().getRootUrl().
concat(API_VERSION + "{link}")).expand(urlVariables);
final String url;
try {
url = URLDecoder.decode(expanded.toString(), "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return getClient().getRestTemplate().
exchange(url, HttpMethod.POST, requestEntity, Foo.class, urlVariables);
}

If all parameters is required you can use #Path annotation.
#Rest(rootUrl = "http://api.lmiforall.org.uk/api/v1/ashe")
public interface MyService {
#Get("/estimateHours?soc={soc}&coarse={coarse}&breakdown={breakdown}&filters={filters}")
ASHEFilterInfo GetEstimateHours(#Path int soc, #Path boolean coarse, #Path String breakdown, #Path String filters);
}
If one of the parameters is optional, there isn't yet a solution that can you can easily pass parameters using Android Annotations. But anybody can contribute to better Android Annotations.

if you define the params for each method then you need to provide them in each request. I thought this was sort of over kill too so what I did was just make a generic get/post request in my api client then just manually enter the values, if you don't define the root url I suppose you could use the QueryStringBuilder class and build the uri that way.
#Rest(rootUrl = "https://path/to/api/", converters = { FormHttpMessageConverter.class,
GsonHttpMessageConverter.class, ByteArrayHttpMessageConverter.class })
public interface ApiClient {
#Get("{uri}")
JsonElement apiGet(String uri);
#Post("{uri}")
JsonObject apiPost(String uri,MultiValueMap data);
RestTemplate getRestTemplate();
void setRootUrl(String rootUrl);
void setRestTemplate(RestTemplate restTemplate);
}
Example usage
JsonElement resp = apiClient.apiGet("method/?random_param=1&another_param=test);
It's not as clean but can be dynamic

Related

ARRAY or OBJECT in Retrofit on Android using TypeAdapter, in a two depth level

I'm struggling with TypeAdapter. Indeed for a json field, I can have an Array (when it's empty) or an Object (when it's not empty). This can't be changed.
Here is the JSON received :
{
"notifications": [
{
...
}
],
"meta": {
"pagination": {
"total": 13,
"count": 13,
"per_page": 20,
"current_page": 1,
"total_pages": 1,
"links": []
}
}
}
The field concerned is links, as you can see the field is inside pagination, which is inside meta. And that's my issue, I don't know how the TypeAdapter has to handle links in a two depth level.
I used this reply to start building a solution. Here it is :
My Custom TypeAdapter class :
public class PaginationTypeAdapter extends TypeAdapter<Pagination> {
private Gson gson = new Gson();
#Override
public void write(JsonWriter out, Pagination pagination) throws IOException {
gson.toJson(pagination, Links.class, out);
}
#Override
public Pagination read(JsonReader jsonReader) throws IOException {
Pagination pagination;
jsonReader.beginObject();
if (jsonReader.peek() == JsonToken.BEGIN_ARRAY) {
pagination = new Pagination((Links[]) gson.fromJson(jsonReader, Links[].class));
} else if(jsonReader.peek() == JsonToken.BEGIN_OBJECT) {
pagination = new Pagination((Links) gson.fromJson(jsonReader, Links.class));
} else {
throw new JsonParseException("Unexpected token " + jsonReader.peek());
}
return pagination;
}
}
My Pagination class :
public class Pagination {
private int total;
private int count;
#SerializedName("per_page")
private int perPage;
#SerializedName("current_page")
private int currentPage;
#SerializedName("total_pages")
private int totalPages;
private Links links;
Pagination(Links ... links) {
List<Links> linksList = Arrays.asList(links);
this.links = linksList.get(0);
}
}
And I'm building my Gson object like that :
Gson gson = new GsonBuilder().registerTypeAdapter(Pagination.class, new PaginationTypeAdapter()).create();
For now my error is : com.google.gson.JsonParseException: Unexpected token NAME
So I know I'm not doing it right, because I'm building my Gson with pagination. But I don't know how it should be handle. Using a TypeAdapter with meta ?
Any help will be welcome, thanks !
When you implement a custom type adapter, make sure that your type adapter has balanced token reading and writing: if you open a composite token pair like [ and ], you have to close it (applies for both JsonWriter and JsonReader). You just don't need this line to fix your issue:
jsonReader.beginObject();
because it moves the JsonReader instance to the next token, so the next token after BEGIN_OBJECT is either NAME or END_OBJECT (the former in your case sure).
Alternative option #1
I would suggest also not to use ad-hoc Gson object instatiation -- this won't share the configuration between Gson instances (say, your "global" Gson has a lot of custom adapters registered, but this internal does not have any thus your (de)serialization results might be very unexpected). In order to overcome this, just use TypeAdapterFactory that is more context-aware than a "free" Gson instance.
final class PaginationTypeAdapterFactory
implements TypeAdapterFactory {
private static final TypeAdapterFactory paginationTypeAdapterFactory = new PaginationTypeAdapterFactory();
private PaginationTypeAdapterFactory() {
}
static TypeAdapterFactory getPaginationTypeAdapterFactory() {
return paginationTypeAdapterFactory;
}
#Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
// Classes can be compared using == and !=
if ( typeToken.getRawType() != Pagination.class ) {
// Not Pagination? Let Gson pick up the next best-match
return null;
}
// Here we get the references for two types adapters:
// - this is what Gson.fromJson does under the hood
// - we save some time for the further (de)serialization
// - you classes should not ask more than they require
final TypeAdapter<Links> linksTypeAdapter = gson.getAdapter(Links.class);
final TypeAdapter<Links[]> linksArrayTypeAdapter = gson.getAdapter(Links[].class);
#SuppressWarnings("unchecked")
final TypeAdapter<T> typeAdapter = (TypeAdapter<T>) new PaginationTypeAdapter(linksTypeAdapter, linksArrayTypeAdapter);
return typeAdapter;
}
private static final class PaginationTypeAdapter
extends TypeAdapter<Pagination> {
private final TypeAdapter<Links> linksTypeAdapter;
private final TypeAdapter<Links[]> linksArrayTypeAdapter;
private PaginationTypeAdapter(final TypeAdapter<Links> linksTypeAdapter, final TypeAdapter<Links[]> linksArrayTypeAdapter) {
this.linksTypeAdapter = linksTypeAdapter;
this.linksArrayTypeAdapter = linksArrayTypeAdapter;
}
#Override
public void write(final JsonWriter out, final Pagination pagination)
throws IOException {
linksTypeAdapter.write(out, pagination.links);
}
#Override
public Pagination read(final JsonReader in)
throws IOException {
final JsonToken token = in.peek();
// Switches are somewhat better: you can let your IDE or static analyzer to check if you covered ALL the cases
switch ( token ) {
case BEGIN_ARRAY:
return new Pagination(linksArrayTypeAdapter.read(in));
case BEGIN_OBJECT:
return new Pagination(linksTypeAdapter.read(in));
case END_ARRAY:
case END_OBJECT:
case NAME:
case STRING:
case NUMBER:
case BOOLEAN:
case NULL:
case END_DOCUMENT:
// MalformedJsonException, not sure, might be better, because it's an IOException and the read method throws IOException
throw new MalformedJsonException("Unexpected token: " + token + " at " + in);
default:
// Maybe some day Gson adds something more here... Let be prepared
throw new AssertionError(token);
}
}
}
}
Alternative option #2
You can annotate your private Links links; with #JsonAdapter and bind a type adapter factory directly to links: Gson will "inject" links objects directly to Pagination instances, so you don't even need a constructor there.

Deserialize in-string JSON using Gson

I am using Retrofit 2 with GsonConverter. The problem is I have this response:
"responseData": {
"data": "<json array>"
}
As you can see one of the parameters is a JSON array, but it is a string. Should I use TypeAdapter and override the read and write methods? If so can you show how I can do this?
As you can see one of the parameters is a JSON array, but it is a string.
If the response generator is under your control, you should definitely change the response format (both for well-formedness and performance (Gson does not allow to read/write string literals as raw values)).
Should I use TypeAdapter and override the read and write methods?
If you cannot control your server response, you have to implement a custom type adapter with the read method implemented only. To align with that response format, you could define custom mappings like these:
final class Response<T> {
final ResponseData<T> responseData = null;
}
final class ResponseData<T> {
// This is where we're telling Gson to apply the special read strategy, not to all types
#JsonAdapter(RawJsonTypeAdapterFactory.class)
final T data = null;
}
As you can see, you just have to bind a custom type adapter to a specific field only. Despite the JsonAdapter annotation accepts TypeAdapter classes as well, you cannot bind TypeAdapter directly because you need Gson and Type instances.
final class RawJsonTypeAdapterFactory
implements TypeAdapterFactory {
// Gson will instantiate it itself without any issues
private RawJsonTypeAdapterFactory() {
}
#Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
// No additional checks here, we're assuming the necessary fields are properly annotated
final Type type = typeToken.getType();
return new TypeAdapter<T>() {
#Override
public void write(final JsonWriter out, final T value) {
throw new UnsupportedOperationException();
}
#Override
public T read(final JsonReader in)
throws IOException {
return gson.fromJson(in.nextString(), type);
}
}.nullSafe(); // And making the type adapter null-safe
}
}
Now JSON documents like
{
"responseData": {
"data": "[1,2,3]"
}
}
can be easily parsed in plain Java:
private static final Type intArrayResponseType = new TypeToken<Response<int[]>>() {
}.getType();
private static final Gson gson = new Gson();
...
try ( final JsonReader jsonReader = getPackageResourceJsonReader(Q43456942.class, "stringified.json") ) {
final Response<int[]> response = gson.fromJson(jsonReader, intArrayResponseType);
System.out.println(Arrays.toString(response.responseData.data));
}
Output:
[1, 2, 3]
Your Retrofit-bound service might have a method declared this (no type tokens necessary since Retrofit is smart enough to pass the Call parameterization to the underlying Gson converter):
Call<Response<int[]>> getIntArray();

Retrofit / OkHttp3 400 Error Body Empty

I am using Retrofit 2 in my Android project. When I hit an API endpoint using a GET method and it returns a 400 level error I can see the error content when I use an HttpLoggingInterceptor, but when I get to the Retrofit OnResponse callback the error body's string is empty.
I can see that there is a body to the error, but I can't seem to pull that body when in the context of the Retrofit callback. Is there a way to ensure the body is accessible there?
Thanks,
Adam
Edit:
The response I see from the server is:
{"error":{"errorMessage":"For input string: \"000001280_713870281\"","httpStatus":400}}
I am trying to pull that response from the response via:
BaseResponse baseResponse = GsonHelper.getObject(BaseResponse.class, response.errorBody().string());
if (baseResponse != null && !TextUtils.isEmpty(baseResponse.getErrorMessage()))
error = baseResponse.getErrorMessage();
(GsonHelper is just a helper which passes the JSON string through GSON to pull the object of type BaseResponse)
The call to response.errorBody().string() results in an IOException: Content-Length and stream length disagree, but I see the content literally 2 lines above in Log Cat
I encountered the same problem before and I fixed it by using the code response.errorBody().string() only once. You'll receive the IOException if you are using it many times so it is advised to just use it as a one-shot stream just as the Documentation on ResponseBody says.
My suggestion is: convert the Stringified errorBody() into an Object immediately as the latter is what you're gonna be using on subsequent operations.
As it was mentioned, you need to use response.errorBody().string() only once. But there is a way to get the error body string more than once.
TL;DR Use the code below to get error body string from response more than once.
public static String getErrorBodyString(Response<?> response) throws IOException {
// Get a copy of error body's BufferedSource.
BufferedSource peekSource = response.errorBody().source().peek();
// Get the Charset, as in the original response().errorBody().string() implementation
MediaType contentType = response.errorBody().contentType(); //
Charset charset = contentType != null ? contentType.charset(UTF_8) : UTF_8;
charset = Util.bomAwareCharset(peekSource, charset);
// Read string without consuming data from the original BufferedSource.
return peekSource.readString(charset);
}
Explanation:
This is based on the original response.errorBody().string() method implementation. It uses the copy of BufferedSource from peek() and returns the error body string without consuming it, so you can call it as many times as you need.
If you look at the response.errorBody().string() method implementation, you'll see this:
public final String string() throws IOException {
try (BufferedSource source = source()) {
Charset charset = Util.bomAwareCharset(source, charset());
return source.readString(charset);
}
}
source.readString(charset) consumes data of the error body's BufferedSource instance, that's why response.errorBody().string() returns an empty string on next calls.
To read from error body's BufferedSource without consuming it we can use peek(), which basically returns a copy of the original BufferedSource:
Returns a new BufferedSource that can read data from this
BufferedSource without consuming it.
you can use Gson to get errorBody as your desired model class:
val errorResponse: ErrorMessage? = Gson().fromJson(
response.errorBody()!!.charStream(),
object : TypeToken<ErrorMessage>() {}.type
)
First create an Error class like below:
public class ApiError {
#SerializedName("httpStatus")
private int statusCode;
#SerializedName("errorMessage")
private String message;
public ApiError() {
}
public ApiError(String message) {
this.message = message;
}
public ApiError(int statusCode, String message) {
this.statusCode = statusCode;
this.message = message;
}
public int status() {
return statusCode;
}
public String message() {
return message;
}
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
}
Second you can create a Utils class to handle your error like below:
public final class ErrorUtils {
private ErrorUtils() {
}
public static ApiError parseApiError(Response<?> response) {
final Converter<ResponseBody, ApiError> converter =
YourApiProvider.getInstance().getRetrofit()
.responseBodyConverter(ApiError.class, new Annotation[0]);
ApiError error;
try {
error = converter.convert(response.errorBody());
} catch (IOException e) {
error = new ApiError(0, "Unknown error"
}
return error;
}
And finally handle your error like below:
if (response.isSuccessful()) {
// Your response is successfull
callback.onSuccess();
}
else {
callback.onFail(ErrorUtils.parseApiError(response));
}
I hope this'll help you. Good luck.
If you are gettig 400 then its a bad request you r trying to send to server.
check your get req.

Android - Simple XML Framework. #Convert interferes with #Attribute - How to solve this?

I was working on capturing the order of elements contained in tag. Here is all the code:
League.java:
#Root
#Convert(value = LeagueConverter.class)
public class League
{
#Attribute
private String name;
#Element(name="headlines", required = false)
private Headlines headlines;
#Element(name="scores", required = false)
private Scores scores;
#Element(name="standings", required = false)
private Standing standings;
#Element(name="statistics", required = false)
private LeagueStatistics statistics;
public List<String> order = new ArrayList<String>();
// get methods for all variables
}
LeagueConverter.java:
public class LeagueConverter implements Converter<League>
{
#Override
public League read(InputNode node) throws Exception
{
League league = new League();
InputNode next = node.getNext();
while( next != null )
{
String tag = next.getName();
if(tag.equalsIgnoreCase("headlines"))
{
league.order.add("headlines");
}
else if(tag.equalsIgnoreCase("scores"))
{
league.order.add("scores");
}
else if(tag.equalsIgnoreCase("statistics"))
{
league.order.add("statistics");
}
else if(tag.equalsIgnoreCase("standings"))
{
league.order.add("standings");
}
next = node.getNext();
}
return league;
}
#Override
public void write(OutputNode arg0, League arg1) throws Exception
{
throw new UnsupportedOperationException("Not supported yet.");
}
}
Exampe of XML:
<android>
<leagues>
<league name ="A">
<Headlines></Headlines>
<Scores></Scores>
...
</league>
<league name ="B">...</league>
</leagues>
</android>
How I'm calling it and expecting it to behave: (Snippet)
Android android = null;
Serializer serial = new Persister(new AnnotationStrategy());
android = serial.read(Android.class, source);
Log.i("Number of leagues found ",tsnAndroid.getLeagueCount() + ""); // prints fine
League nhl = tsnAndroid.getLeagues().get(0); // works fine
// DOES NOT WORK throws NullPointerEx
League nhl2 = tsnAndroid.getLeagueByName("A");
// DOES NOT WORK throws NullPointerEx
for(String s : nhl.getOrder())
{
Log.i("ORDER>>>>>", s);
}
The problem:
android.getLeagueByName() (Works with #Attribute name) suddenly stops working when I have the converter set, so its like the following from League.java, never gets set.
#Attribute
private String name; // not being set
However, when I comment out the converter declaration in League.java - Every league has an attribute called name and android.getLeagueByName() starts working fine...
Does #Convert for League somehow interfere with #Attribute in League?
Even though this question is outrageously old (as is the SimpleXML library), I will give my two cents.
#Convert annotation works only with #Element, but it does not have any effect on #Attribute. I'm not sure if that's a bug or a feature, but there is another way of handling custom serialized objects - called Transform with Matcher, and it works both with Attributes and with Elements. Instead of using the Converters, you define a Transform class that handles serialization and deserialization:
import java.util.UUID;
import org.simpleframework.xml.transform.Transform;
public class UUIDTransform implements Transform<UUID> {
#Override
public UUID read(String value) throws Exception {
return value != null ? UUID.fromString(value) : null;
}
#Override
public String write(UUID value) throws Exception {
return value != null ? value.toString() : null;
}
}
As you can see, it is more straight-forward than implementing the Convert interface!
Create a similar class for all your objects that require custom de/serialization.
Now instantiate a RegistryMatcher object and register there your custom classes with their corresponding Transform classes. This is a thread-safe object that internally uses a cache, so it might be a good idea to keep it as a singleton.
private static final RegistryMatcher REGISTRY_MATCHER = new RegistryMatcher();
static {
try {
REGISTRY_MATCHER.bind(UUID.class, UUIDTransform.class);
// register all your Transform classes here...
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Finally, you can create a Persister class each time before a conversion and pass it the AnnotationStrategy together with your RegistryMatcher instance. In this factory method below, we will also use an indenting formatter:
private static Persister createPersister(int indent) {
return new Persister(new AnnotationStrategy(), REGISTRY_MATCHER, new Format(indent));
}
Now you can make your serialization/deserialization methods:
public static String objectToXml(Object object, int indent) throws MyObjectConversionException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
Persister p = createPersister(indent);
try {
p.write(object, out, "UTF-8");
return out.toString("UTF-8");
} catch (Exception e) {
throw new MyObjectConversionException("Cannot serialize object " + object + " to XML: " + e.getMessage(), e);
}
}
public static <T> T xmlToObject(String xml, final Class<T> clazz) throws MyObjectConversionException {
Persister p = createPersister(0);
try {
return (T) p.read(clazz, xml);
} catch (Exception e) {
throw new MyObjectConversionException(
"Cannot deserialize XML to object of type " + clazz + ": " + e.getMessage(), e);
}
}
The only issue with this approach is when you want to have different formatting for the same object - e.g. once you want the java.util.Date to have just the date component, while later on you also want to have the time component. Then just extend the Date class, calling it DateWithTime, and make a different Transform for it.
#ElementListUnion will capture the order of elements
The #Convert annotation works only on #Element fields. I am struggling against converting #Attribute fields too but with no success for now...

How to properly mock HttpGet call on Android test

I've got an application that performs HTTP GET calls using HttpGet and I would like to mock the response in order to test different scenarios without having to setup any specific local server that would act like the remote one.
The goal is to have very high level tests that acts like a real user (Robotium) and fake the response that the application would obtain calling the real server. Much like testing a Twitter client, if you need an example.
Ok, so this is what I did to get fake HttpResponses in my Robotium tests:
- I have a class HttpCallBuilder, that usually just returns a DefaultHttpClient
- I added a setHttpClient() method to set a MockHttpClient in my tests (you need to implement (empty) a lot of methods in the HttpClient interface, which I omitted here):
public class MockHttpClient implements HttpClient {
private static Context context;
private final BasicHttpParams params = new BasicHttpParams();
#Override
public HttpResponse execute(HttpUriRequest request) throws IOException,
ClientProtocolException {
InputStream mockInputStream = context.getAssets().open(
MockResponses.forRequest(request));
return new MockHttpResponse(mockInputStream);
}
#Override
public HttpParams getParams() {
return params;
}
public static void setContext(Context applicationContext) {
MockHttpClient.context = applicationContext;
}
}
MockResponses allows you to prime your Mock with the right responses for the situation:
public class MockResponses {
private static final List<String[]> responseMapping = new ArrayList<String[]>();
private static final String BASE = "mocks/";
public static String forRequest(final HttpUriRequest request) {
final String requestString = request.getURI().toString();
for (final String[] mapping : responseMapping) {
if (requestString.matches(mapping[0])) {
return BASE + mapping[1];
}
}
throw new IllegalArgumentException(
"No mocked reply configured for request: " + requestString);
}
public static void forRequestDoAnswer(final String regex,
final String fileToReturn) {
responseMapping.add(new String[] { regex, fileToReturn });
}
public static void reset() {
responseMapping.clear();
}
}
In your test you can then prepare your test like this:
HttpCallBuilder.setHttpClient(new MockHttpClient());
MockHttpClient.setContext(context);
MockResponses.reset();
MockResponses.forRequestDoAnswer(".*method=Login.*", "loginform.html");
Google provides a library named as Mockwebserver which can be used for mocking web service response. https://code.google.com/p/mockwebserver/ You can refer this link
How about using Mockito ?
According to this article its latest version should support dalvik, so you should be able to use it with robotium.
With mockito you can mock any object to return whatever you want. I found it very powerful and concise.
Try XML Mimic, that will solve your problem. It is easy to configure and runs as independent server.
http://sourceforge.net/projects/xmlmimic/

Categories

Resources