I use android annotations to communicate with the server. In one of the api calls I need to send some text data and an image, say, from gallery.
#Post("/items/addItem.php")
String addItem(Protocol protocol);
How do I attach a MultipartForm with an image along with the post request?
Just use the right Spring converter : FormHttpMessageConverter.
However, this converter only accepts MultiValueMap as method parameter. Please have a look at these two issues: #652 and #660.
If you really want to use any object as parameter, you have to implement your own custom FormHttpMessageConverter which will handle that by using reflection.
DayS is right. An as quotation, you must include the FormHttpMessageConverter in your Rest Interface definition inside the converters array:
#Rest(rootUrl = "http://api.yourapp.com", converters = {
MappingJacksonHttpMessageConverter.class,
StringHttpMessageConverter.class, FormHttpMessageConverter.class })
public interface YourAppApiClient {
#Post("/items/addItem.php")
void getCustomerInformation(MultiValueMap formfields);
}
-Totaly Agree with above answers but for use of mappinjacksonhttpmessageconverter you have to add another library so if you dnt want to use it you can use below example
Or you can consider it as another example also :)
#Rest(rootUrl = CommonUtils.BASE_URL, converters = { ByteArrayHttpMessageConverter.class,
FormHttpMessageConverter.class, StringHttpMessageConverter.class })
public interface CustomRest extends RestClientErrorHandling{
#Post(CommonUtils.pUrlLogin)
String _Login(MultiValueMap<String, Object> multiValueMap);
#Post(CommonUtils.pUrlSignUp)
String _SignUp(MultiValueMap<String, Object> multiValueMap);
}
Related
public class Data{
public String str; //String (that may contain line breaks) I need to serialize as it is.
}
Why I needed custom Serializer for string?
Without custom serializer it serializes this as object {"str":{"count": 292,"hashCode": 0} }
I need it to be {"str":"..............."}
How to do it with custom Serializer?
There are example of custom serializer for custom types, but could not find anything that helps to serialize String type.
Well, Gson supports strings out of box and you don't have to implement any string serializer and vice versa yourself. What I guess might happen to your case is merely importing a wrong string class, say import foo.bar.baz.String; or less obvious import foo.bar.baz.*, or you just have a String class implementation right in the package where your Data class is declared in. (This cannot explain what values were really assigned to str, though, -- it would never work in Java causing ClassCastException). A wrong class might be indicated with numeric count and hashCode without any char[]-declared fields, so I don't believe this is a java.lang.String in your case. Also, a more hypothetical thing here might be use of reflection that discarded the string type adapter out of your Gson instance, no matter how and how weird it sounds. In any case, you don't have to implement even a single line to serialize Java strings with Gson.
Regarding the accepted answer: it is suboptimal. If, for whatever reason, there is nothing wrong with your imports, your package does not declare a custom String class, and your Gson instances do not suffer from reflection surgery, but Gson still serializes such strings as nested objects (have no ideas why then), you'd only need a single special String type adapter without any need of creating type adapters for any class that uses that weird String as a field:
final Gson gson = new GsonBuilder()
.registerTypeAdapter(/*real.package.here.*/String.class, (JsonSerializer</*real.package.here.*/String>) (s, type, context) -> new JsonPrimitive(s.toString())) // whatever the real Java string is obtained
.create();
Try this
public class DataSerializer implements JsonSerializer<Data> {
#Override
public JsonElement serialize(Data data, Type typeOfSrc, JsonSerializationContext context) {
JsonObject object = new JsonObject();
object.addProperty("src", data.src);
return object;
}
}
Add this to Gson Like this
Gson gson = new GsonBuilder()
.registerTypeAdapter(Data.class, new DataSerializer())
.create();
In my andorid app I am making a GET request using Retrofit2:
http://myapi.com/items/list
But I would also like to make another request e.g.
http://myapi.com/items/list/filter/active:true,min_price:100
So the filter parameter is optional. I am trying to do the following:
#GET("items/items/list{filter}")
Observable<ResponseItems> getItems(#Path("filter") String filter);
and calling it like:
service.getItems("")
and:
service.getItems("/filter/active:true,min_price:100")
But it does not work. So I ended up creating two separate service calls, one with filter param and other without. I think that there should be more elegant method though.
So i've seen what you are trying to achieve.
How your api declaration should looks like:
#GET("items/list/{filter}")
Observable<ResponseItems> getItems(#Path(value = "filter", encoded = true) String filter);
and a call service.getItems("") would lead to http://myapi.com/items/list/ be called
a call service.getItems("filter/active:true,min_price:100") would lead to
http://myapi.com/items/list/filter/active:true,min_price:100 be called.
An encoded property in #Path annotation is set because your optional path parameter contains / and retrofit encodes it without that property.
So as i wrote in comments better use two declarations:
#GET("items/list/")
Observable<ResponseItems> getItems();
#GET("items/list/filter/{filter}")
Observable<ResponseItems> getItems(#Path(value = "filter") String filter);
so you may call it like service.getItems("active:true,min_price:100")
In simple word make method over loading. Create two method with same name and different parameter. Check my below source code. (written in kotlin)
#GET("myportal/news/{id}")
fun getNewsList(#Path("id") id: String): Call<NewsEntity>
#GET("myportal/news/{id}/{dateTime}")
fun getNewsList(#Path("id") id: Long, #Path("dateTime") dateTime: String): Call<NewsEntity>
Its better to use HashMap to send optional params in a request, this allows you to send single/multiple optional params in your request also if you send the HashMap empty it will not affect your request.
Your interface will contain code like snippet below
#POST("yourUrl")
#FormUrlEncoded
Call<YourResponse> yourApiRequest(#Header("Authorization") String token,
#Field("mandatoryParam") int mandatoryParam,
#FieldMap Map<String, String> optionalParamMap);
And your API call will be something like the following
private HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("optionalParam1", value1);
hashMap.put("optionalParam2", value2);
ApiClient.getApiClient().getApiInterface().yourApiRequest(token,
mandatoryParam, hashMap)
.enqueue(new Callback<YourResponse>() {
#Override
public void onResponse(Call<YourResponse> call, Response<YourResponse> response) {
}
#Override
public void onFailure(Call<YourResponse> call, Throwable t) {
}
});
In a case where you don't want to send any optional params you can pass an empty hashmap to your request.
I am using retrofit in my android application but my service sometimes return object data type and sometime array datatype. how can i handle this ? i used object in place of data type in android but am not able to use it properly.
Create an Interface,inside the Interface whenever your service returns a List do like this:
public Interface EndPointInterface{
#GET(Constants.URL_GET_PHARMACY_REPORT)
Call<List<PharmacyReport>> getPharmacyReport(#Query(Constants.PATIENT_ID) String patientId);
}
else if your service returns an Object proceed like this:
public Interface EndPointInterface{
#GET(Constants.URL_FETCH_STORE_INFO)
Call<Store> getStoreInfoByBeaconUUID(#Query(Constants.BEACON_UUID) String beaconUUID);
}
I am using Retrofit to Post form data and recieve back XML. What I have so far works fine but i want to make some changes. Here is my existing code (and it works):
Here is my interface
public interface SignupUser
{
#FormUrlEncoded
#POST("/createaccount.cfm")
SignupServerResponse signup(#Field("e") String email, #Field("p") String password);
}
Here is the code to call the api (again, this works fine, I will explain below what I want to change)
SignUpDetails mDeets; // this gets initialize and set somewhere else
RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint("http://myurl.com")
.setConverter(new SimpleXMLConverter()).build(); // the response is xml, that works fine
SignupUser service = restAdapter.create(SignupUser.class);
SignupServerResponse res = service.signup(mDeets.getE(), mDeets.getP());
How can I make it so that I can pass the SignUpDetails object straight to the signup() method instead of passing in separate Strings? When I change the constructor of signup() to accept SignUpdetails object (see below) and pass my SignUpDetails object in, I get an error saying
No Retrofit Annotation Found
Here is how I would like to define the interface
public interface SignupUser
{
#FormUrlEncoded
#POST("/createaccount.cfm")
SignupServerResponse signup(SignUpDetails deets);
}
And call it like this (instead of passing in all those parameters)
SignupServerResponse res = service.signup(mDeets);
I tried adding #Field above each of my variables in the SignUpDetails class and that doesnt work either (compilation error)
On your interface use #Body annotation for the deets parameter:
#POST("/createaccount.cfm")
SignupServerResponse signup(#Body SignUpDetails deets);
That should convert SignUpDetails into XML (since you use xml converter on your adapter).
It is then your responsibility to parse the XML request body on server.
In android, I'm using model classes with methods to handle the data manipulation. My data is brought in from webservices as json. I'm contemplating the possibility of using JSONObjects to store the values of class level attributes. But, I don't know of a way to use the JSONObj as the "holder" variable and create access methods. I don't want to predetermine these methods, as jsonRepository should hold the values, not always known at design time
For example, I'd like to have:
public class User {
private JSONObject jsonAttributes;
public User(String json) {
this.jsonAttributes= new JSONObject(json);
}
[IMPLICIT attribute access methods]
public string Prop1() returns jsonAttributes.getString("prop1");
public string Prop1(String newProp1) returns jsonAttributes.putString("prop1",newProp1);
public string Prop2() returns jsonRepository.getString("id");
public string Prop2(String newProp2) returns jsonAttributes.putString("prop2",newProp2);
....
from outside this class then, I would access the attributes simply...
User myUser = new User(someValidJson);
String myString = myUser.Prop1
Misguided? If not, how does one manage implicit property setting/getting?
As was mentioned in the comment above, why not create your user class, with all of the relevant memeber variables, and simply parse your JSON data in order to populate the ionformation in your user class.
There are a lot of ways you can do this, but I would consider using the builder pattern, as it is flexible, which could be useful if your JSON data changes in the future.