Retrofit and usage of absolute URLs - retrofit

How can you handle in Retrofit absolute URLs for some calls?
I am using a combination of dagger, retrofit and OKHttp. I provide a #Singleton RestAdapter with the selected endpoint (Production, Staging, etc) which it is formed from the BASE URL.
#Provides
#Singleton
RestAdapter providesRestAdapter(Endpoint endpoint,
ObjectMapper jacksonObjectMapper,
Client client,
ApiRequestInterceptor headers) {
return new RestAdapter.Builder() //
.setClient(client) //
.setEndpoint(endpoint) //
.setConverter(new JacksonConverter(jacksonObjectMapper))
.setLogLevel(RestAdapter.LogLevel.FULL)
.setRequestInterceptor(headers) //
.build();
}
The problem is that the REST service, for some cases, returns the URL for the content to be loaded in ABSOLUTE format meaning something like http://someurl.com/resource?sort=ascendent and not the preferable /resouce?sort=ascendent (without the BASE_URL)
Now the question is how I can create the interface of the service to deal with such scenario?
I was thinking something like:
public interface PlaceholdersService {
#GET("{placeholderHref}")
public void getPlaceholder(#EncodedPath("placeholderHref") String placeholderHref);
}
The problem is that I am not sure if the BASE URL set in the Endpoint previously when creating the RestAdapter will be added (can't test it at the moment).
Another though was to create a new RestAdapter specially for this case with an Endpoint set to a null or empty string fixed point like Endpoints.newFixedEndpoint(null) or Endpoints.newFixedEndpoint("").
Any suggestions?
Thanks

Digging a little bit I just realised there is an open issue for this manner in Github https://github.com/square/retrofit/issues/333
It has been moved the discussion to the V2 of the library to discuss if will be supported or not in that version.
This means that if supported, won't do it for a while. Is there any suggestion or workaround you can suggest to surpass this issue for the moment?

I had a similar problem and I solved it by creating new adapter with specified URL and use an empty path in my interface. Here is my question and my own answer.
Hope it helps.

Related

SonarQube complains about using ResponseEntity with a wildcard

I use SpringBoot for REST web services development and SonarQube for static analysis.
I have a few endpoints in my application that look the following way:
#PostMapping
ResponseEntity<?> addSomething(#RequestBody Some object) {
// some code there
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
SonarQube complains about using ResponseEntity with a wildcard, reporting me a Critical issue "Generic wildcard types should not be used in return parameters".
I wonder if I should disable this verification in SonarQube or come up with something different for return type for these cases.
What do you think about it?
#PostMapping
ResponseEntity<Object> addSomething(#RequestBody Some object) {
// some code there
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
This will also remove the error. It is still very generic, but it is one of the solutions if you want to return different types based on the outcome. For instance:
#PostMapping
ResponseEntity<Object> addSomething(#RequestBody Some object) {
//Will return ResponseEntity<> with errors
ResponseEntity<Object> errors = mapValidationService(bindingResult);
if (!ObjectUtils.isEmpty(errors)) return errors;
// some code there
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
So actually i find the rule pretty self describing:
Using a wildcard as a return type implicitly means that the return value should be considered read-only, but without any way to enforce this contract.
Let's take the example of method returning a "List". Is it possible on this list to add a Dog, a Cat, ... we simply don't know. The consumer of a method should not have to deal with such disruptive questions.
https://sonarcloud.io/organizations/default/rules#rule_key=squid%3AS1452
So Actually in your case, you do not want any kind of Class in there, you specifically want an Serializable-object - for obvious reasons: it should be serialized later on
So instead of using ? it would be more suitable in your case to use Serializable. This is always case dependent, but normally you definitly expect some kind of common interface or base class as a return value. Hence that, the follow up developer, definitly knows what he can expect, and what kind of functionality he definitly can use.
Finally I've removed <?> from return value, so the code looks like the following now:
#PostMapping
ResponseEntity addSomething(#RequestBody Some object) {
// some code there
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
SonarQube doesn't complain anymore and code seems a little bit simpler now.

Is there a simple way to solve content negotiation in Spring boot

We plan to use content type negitiation as a form of versioning for our rest API but it seems more complex than it should be.
Given the follwing example code :
#RestController
#RequestMapping("/products")
ProductController {
.......
#RequestMapping(value = "/{productID}", method = RequestMethod.GET, produces = "productVersion2/json")
public ResponseEntity<ProductV2> getVersion2(#PathVariable String productID) {
.......
return new ResponseEntity<ProductV2>(product, HttpStatus.OK);
The correct method is being called when test this from e.g postman, but i get a HTTP 406 Not Acceptable as a response. I have been looking several places, but I have not found a a page with a good explanation of what i need to do to make this work.
The response is to be parsed with json just like all other requests, but the response object is modified.
The thought is that we by doing this can support several "versions" of the same API and we can gradually make clients move over to the new api, while still having the same uri/resource to access.
Can anyone point to a good tutirial or a step by step guide of how this can be solved in spring boot ?
I have read this article : http://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc/#combined-controller
but I was not able to get a clear anderstanding of what was needed to make it work
Your media type is wrong. To use custom media types for API versioning you could use application/productVersion2+json instead of productVersion2/json. I suspect you get the 406 because Spring Boot has no way to find out how to serialize your object into JSON because productVersion2/json isn't a valid media type for json data.
There is more than one way to pick a media type to do this, I've googled a more comprehensive document here.

Configure Autofac Container for background thread

I have an asp.net MVC site which has many components registered using an InstancePerHttpRequest scope, however I also have a "background task" which will run every few hours which will not have an httpcontext.
I would like to get an instance of my IRepository which has been registered like this
builder.RegisterGeneric(typeof(EfRepository<>)).As(typeof(IRepository<>))
.InstancePerHttpRequest();
How do I do this from a non http context using Autofac? I think the IRepository should use the InstancePerLifetimeScope
There are several ways of how you can do that:
The best one in my opinion. You can register the repository as InstancePerLifetimeScope as you said. It works with HttpRequests and LifetimeScopes equally well.
builder.RegisterGeneric(typeof(EfRepository<>)).As(typeof(IRepository<>))
.InstancePerLifetimeScope();
Your registration for HttpRequest may differ from registration for LifetimeScope, then you can have two separate registrations:
builder.RegisterGeneric(typeof(EfRepository<>)).As(typeof(IRepository<>))
.WithParameter(...)
.InstancePerHttpRequest(); // will be resolved per HttpRequest
builder.RegisterGeneric(typeof(EfRepository<>)).As(typeof(IRepository<>))
.InstancePerLifetimeScope(); // will be resolved per LifetimeScope
You can explicitly create "HttpRequest" scope using its tag. Exposed through MatchingScopeLifetimeTags.RequestLifetimeScopeTag property in new versions.
using (var httpRequestScope = container.BeginLifetimeScope("httpRequest")) // or "AutofacWebRequest" for MVC4/5 integrations
{
var repository = httpRequestScope.Resolve<IRepository<Entity>>();
}

Autofac Multi-tenant IoC Container in an ASP.NET Web API Application

Autofac 3.0 will have a MultitenantIntegration support and its preview release is out now. To try it out, I created an ASP.NET Web API application with the following configuration:
public class Global : System.Web.HttpApplication {
protected void Application_Start(object sender, EventArgs e) {
var config = GlobalConfiguration.Configuration;
config.Routes.MapHttpRoute("Default", "api/{controller}");
RegisterDependencies(config);
}
public void RegisterDependencies(HttpConfiguration config) {
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// creates a logger instance per tenant
builder.RegisterType<LoggerService>().As<ILoggerService>().InstancePerTenant();
var mtc = new MultitenantContainer(
new RequestParameterTenantIdentificationStrategy("tenant"),
builder.Build());
config.DependencyResolver = new AutofacWebApiDependencyResolver(mtc);
}
}
It gets the job done and creates a LoggerService instance as ILoggerService per tenant. I have two problems at this stage which I wasn't able to solve:
I used out of the box provided RequestParameterTenantIdentificationStrategy here as the TenantIdentificationStrategy just for this demo application. I am able to create my custom TenantIdentificationStrategy by implementing ITenantIdentificationStrategy interface. However, TryIdentifyTenant method of the ITenantIdentificationStrategy makes you rely on a static instance such as HttpContext.Current which is something that I don't want in an ASP.NET Web API environment as I want my API to be hosting agnostic (I know that I can delegate this work to the hosting layer but I would rather not to). Is there another way to achieve this in a way that I won't rely on a static instance?
I also have a chance to register tenant specific instance as below:
mtc.ConfigureTenant("tenant1", cb => cb.RegisterType<Foo>()
.As<IFoo>().InstancePerApiRequest());
However, one of my situations requires me to pass the tenant name through the constructor parameter and I would love to have something like below:
mtc.ConfigureTenant((cb, tenantName) => cb.RegisterType<Foo>()
.As<IFoo>()
.WithParameter("tenantName", tenantName)
.InstancePerApiRequest());
Currently there is no such an API. Is there another way to achieve this or this kind of requirement doesn't make any sense?
Multitenant support has been available for a long time, it's just that 3.0 is the first time we've had a NuGet package for it. :)
The RequestParameterTenantIdentificationStrategy is, as documented, just a very simple example showing one possible (and not recommended) way to identify tenant. You will have to choose for yourself how to identify your tenant based on the operating context. It could be from a web.config value, an environment variable, or some other thing in the current environment. If you don't want to use HttpContext.Current, don't. It's up to you to pick where you get that info from.
(A note on the RPTIStrategy - the part that isn't recommended is using a querystring or request parameter as the tenant ID mechanism. I use HttpContext in my production apps and it works fine. There's only so much you can abstract out before you have to actually touch the bare metal.)
There is no way out of the box to provide the lambda registration syntax you're asking for, primarily because tenant is not passed through the resolution process. The resolution process is:
Identify the tenant with the strategy.
Find the tenant's configured lifetime scope.
Use standard Autofac Resolve style syntax.
It's intentionally simple and analogous to the existing operations. At the time of resolve, the sub-lifetime-scope belonging to the tenant is tagged with the tenant ID but the resolution operation doesn't know about the tenant ID... so the lambda wouldn't work (and probably won't anytime soon because it'd change the fundamental internals of the way Autofac works if it did).
To accomplish what you're looking for, you can use a combination of the InstancePerTenant extension when registering...
var builder = new ContainerBuilder();
builder.RegisterType<Foo>().As<IFoo>().InstancePerTenant();
...and registering the ITenantIdentificationStrategy as a dependency in your container.
builder.Register(myIdStrategy).As<ITenantIdentificationStrategy>();
Then make your class take an ITenantIdentificationStrategy rather than the tenant ID directly. Use the strategy to get the tenant ID instead.
If you REALLY want to get fancy, you could register a keyed lambda that resolves the ID strategy, then gets the tenant ID. Then you could add a parameter registration to the object like you did but using a keyed service. (I'm going to go by memory now, so you'll have to double-check my syntax here, but it'll be something like this...)
builder.Register(c =>
{ var s = c.Resolve<ITenantIdentificationStrategy>();
object id;
s.TryIdentifyTenant(out id);
return id;
}).Keyed<object>("tenantId");
builder.RegisterType<Foo>()
.As<IFoo>()
.WithParameter(
(pi, c) => pi.Name == "tenantId",
(pi, c) => c.ResolveKeyed<object>("tenantId"))
.InstancePerApiRequest();
Again, you'll want to double-check me on that, but I'm pretty sure that (or a minor variation) should work to get you what you want.

Flex: Unexpected leakage with RemoteObject + IExternalizable?

I've been tinkering with IExternalizable, but I've noticed some unexpected behavior. I've got this class:
public function readExternal(input:IDataInput):void {
input.readObject();
input.readObject();
input.readObject();
}
public function writeExternal(output:IDataOutput):void {
output.writeObject("first string");
output.writeObject(424242);
output.writeObject("second string");
}
But when I try to serialize this class using AMF and send it to a remote server (via RemoteObject), Charles shows me that the request looks like this:
unexpected result http://img.skitch.com/20100406-cjawastycagp1x2chbe76k2suu.png
But it seems wrong that my serialized object is leaking out into the rest of the request.
So, what am I doing wrong? Is there some part of the documentation I've missed?
You code seems fine, however you should serialize using the proper methods (writeUTF for strings, writeInt for int etc). Anyway Charles seems to not work properly with objects implementing IExternalizable (I'm using version 3.4.1), so you should not rely on what it is showing.
Not directly related to your question - do you really need to use IExternalizable? You are going to lose some benefits related to AMF compression algorithm (unless you are not going to implement all this things in your writeExternal method).

Resources