Java Annotation Processor handle modified source code positions - java

I'm writing custom annotation processor and got struggling with code elements' positions.
Imagine I have the code:
public class DummyStepClass {
#Step
public void getInfo() throws Exception {
HttpClient client = HttpClient.newBuilder().build();
#Remember("REQUEST") HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("https://postman-echo.com/get"))
.GET()
.build();
#Remember("RESPONSE") HttpResponse<String> response =
client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
}
}
Purpose of annotation is to save variable into context of a program flow through my steps.
Context class:
public class Context {
private static final HashMap<String, Object> storage = new LinkedHashMap<>();
private Context() {}
public static void save(String k, Object v) {
storage.put(k, v);
}
}
Literally I want to achieve invoking Context.save(k, v); when annotated rather than writing it every time.
So as a result I want to have something like this:
public class DummyStepClass {
#Step
public void getInfo() throws Exception {
HttpClient client = HttpClient.newBuilder().build();
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("https://postman-echo.com/get"))
.GET()
.build();
Context.save("REQUEST", request);
HttpResponse<String> response =
client.send(request, HttpResponse.BodyHandlers.ofString());
Context.save("RESPONSE", request);
System.out.println(response.statusCode());
System.out.println(response.body());
}
}
I do generate this lines of code and they appears in .class files. However this two statements are added in the end of a method.
How can I handle this?

I've managed to make this work by hooking into "blocks" of java code and pasting my code at the end.

Related

OKHTTP GET and POST request return empty body message

I want to a upload file on my server and I've decided to try OKHTTP instead of my current method which is based on android own HTTP implementation and AsyncTask.
Anyway, I used OKHTTP and its asynchronous implementation (from its own recipes) but it returns an empty message (the request code is ok, the message is empty) in both GET and POST methods.
Did I implement it wrong or is there anything else remained that I did not considered? In the meantime, I couldn't find a similar case except this which says used AsyncTask.
Here's the code:
Request request;
Response response;
private final OkHttpClient client = new OkHttpClient();
private static final String postman_url = "https://postman-echo.com/get?foo1=bar1&foo2=bar2";
String message_body;
public void Get_Synchronous() throws IOException
{
request = new Request.Builder()
.url(postman_url)
.build();
Call call = client.newCall(request);
response = call.execute();
message_body = response.toString();
//assertThat(response.code(), equalTo(200));
}
public void Get_Asynchronous()
{
request = new Request.Builder()
.url(postman_url)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
public void onResponse(Call call, Response response)
throws IOException
{
message_body = response.toString();
}
public void onFailure(Call call, IOException e)
{
}
});
}
Edit:
I catch the log on response:
onResponse: Response{protocol=h2, code=200, message=, url=https://postman-echo.com/get?foo1=bar1&foo2=bar2}
OK, for anyone who wants to receive an string from a call, response and response.messgage() don't provide that. To catch the response from your provider, you just need to call response.body().string() inside onResponse which returns the message inside your request.
But after all, Retrofit is a better choice if you want to receive a JSON file using
.addConverterFactory(GsonConverterFactory.create(gson)).
If you still want to receive an string just use .addConverterFactory(ScalarsConverterFactory.create()) as explained here.

How to access variables in application.properties file

In the java 15 project I have file application.properties of yml type:
NetanyaInfo:
HydrantPoints: https://www.data.com/
I need to use suiteUrlin in the function:
public String getHydrantPoints() throws IOException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.GET()
.uri(URI.create(suiteUrl))//here
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
return response.body();
}
My question is how to get suiteUrl value from the java function?
If this is spring-boot, you do not need anything "special", it will be done for you under the hood. What you do is:
define that application.properties/yaml in src/main/resources
inject that value (almost) anywhere you want
For example:
#Value("${tridelInfo.siteUrl}")
private String siteUrl;
or even inside any bean, via a constructor:
#Bean/#Service/#Component
public class YourBean {
private final String siteUrl;
public YourBean(#Value("${tridelInfo.siteUrl}") String siteUrl) {
this.siteUrl = siteUrl;
}
}
Under the hood, you actually need to define a PropertySourcesPlaceholderConfigurer, but spring-boot does that for you.
There are some options available for this in spring. You can use any of them.
Injecting org.springframework.core.env.Environment to your bean.
#Autowired
private Environment env;
...
public String getTridelSuites() throws IOException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.GET()
.uri(URI.create(env.getProperty("suiteUrl");))//here
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
return response.body();
}

Java HttpClient - second call always fails

I am using java.net.http.HttpClient in my Java Spring Boot app and I noticed this weird behaviour.
When my code call HTTP request to 3rd party API, next request to different 3rd party API returns always as bad request (400). When I execute this request first, it works just fine.
When I restart the app, first API call is always successful, but second one is always bad and so I have to call it again after some timeout and then it work.
So I was thinking, if there is any form of "cache" that remember previous settings or whatever from previous request, because second request to different API is always bad. When I inspected HttpRequest in debugger, it seems okay to me and there was nothing really different from the one that worked.
Here is my bean config
#Configuration
public class HttpClientBean {
#Bean
public HttpClient httpClient() {
return HttpClient.newHttpClient();
}
}
HttpRequest builder
public static HttpRequest buildGetRequest(final String url) {
return HttpRequest.newBuilder()
.uri(URI.create(url))
.GET()
.build();
}
public static HttpRequest buildPostRequest(final String url, final String body) {
return HttpRequest.newBuilder()
.version(HttpClient.Version.HTTP_1_1)
.uri(URI.create(url))
.setHeader(CONTENT_TYPE, APPLICATION_JSON)
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
}
and here is HttpService
#Service
public class HttpServiceImpl implements HttpService {
private final HttpClient httpClient;
#Autowired
public HttpServiceImpl(final HttpClient httpClient) {
this.httpClient = httpClient;
}
#Override
public HttpResponse<String> sendGetRequestWithParams(final String url, final String params) throws Exception {
final HttpRequest request = buildGetRequest(url, params);
return httpClient.send(request, HttpResponse.BodyHandlers.ofString());
}
#Override
public HttpResponse<String> sendGetRequestWithoutParams(final String url) throws Exception {
final HttpRequest request = buildGetRequest(url);
return httpClient.send(request, HttpResponse.BodyHandlers.ofString());
}
#Override
public HttpResponse<String> sendPostRequestWithBody(final String url, final String body) throws Exception {
final HttpRequest request = buildPostRequest(url, body);
return httpClient.send(request, HttpResponse.BodyHandlers.ofString());
}
}
Thank you for your advices.

Okhttp3: Need help to use HeaderInterceptor

I would like to use a global header for all my requests. Therefore I have implemented the following class:
public class HeaderInterceptor {
public Response intercept(Chain chain) throws IOException {
Request request = chain.request()
.newBuilder()
.method("GET", null)
.addHeader("Accept", "application/json")
.addHeader("Basic ", "abcdefghi123456789")
.build();
Response response = chain.proceed(request);
return response;
}
}
Now I would like to do the following in the main()-method:
public static void main(String[] args) throws Exception {
OkHttpClient httpClient = new OkHttpClient.Builder().addInterceptor(MyInterceptor).build();
Request reqAllProjects = new Request.Builder()
.url("https://example.com/projects")
.build();
Response resAllProjects = httpClient.newCall(reqAllProjects).execute();
String responseData = resAllProjects.body().string();
System.out.println(responseData);
}
I'm not sure now how to use my HeaderInterceptor. I guess I'll have to enter it here, right?
OkHttpClient httpClient = new OkHttpClient.Builder().addInterceptor(??MyInterceptor??).build();
I tried something like this: addInterceptor(HeaderInterceptor.intercept()) but this is not working...
Can someone help me please? And does the rest of it look fine? Many thanks in advance!
The interceptor class that you have created doesn't seem to be implementing the Interceptor interface. You need to implement as below
public class HeaderInterceptor implements Interceptor {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request()
.newBuilder()
.addHeader("Accept", "application/json")
.addHeader("Basic ", "abcdefghi123456789")
.build();
Response response = chain.proceed(request);
return response;
}
}
Do note that you should not be modifying the method and body of the request as .method("GET", null) unless you actually need so, as it can result in all the HTTP requests made by the client to make GET requests with null body.
Then add the interceptor while building the client as below
OkHttpClient httpClient = new OkHttpClient.Builder()
.addInterceptor(new HeaderInterceptor()).build();
Have a look at the OkHttp documentation for more info.
Have you checked this question : Okhttp3: Add global header to all requests error
It should be something like
.addInterceptor(new Interceptor())

Android Retrofit Parameterized #Headers

I am using OAuth and I need to put the OAuth token in my header every time I make a request. I see the #Header annotation, but is there a way to make it parameterized so i can pass in at run time?
Here is the concept
#Header({Authorization:'OAuth {var}', api_version={var} })
Can you pass them in at Runtime?
#GET("/users")
void getUsers(
#Header("Authorization") String auth,
#Header("X-Api-Version") String version,
Callback<User> callback
)
Besides using #Header parameter, I'd rather use RequestInterceptor to update all your request without changing your interface. Using something like:
RestAdapter.Builder builder = new RestAdapter.Builder()
.setRequestInterceptor(new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
request.addHeader("Accept", "application/json;versions=1");
if (isUserLoggedIn()) {
request.addHeader("Authorization", getToken());
}
}
});
p/s : If you are using Retrofit2, you should use Interceptor instead of RequestInterceptor
Since RequestInterceptor is not longer available in Retrofit 2.0
Yes, you can pass them in runtime. As a matter of fact, pretty much exactly as you typed it out. This would be in your API interface class, named say SecretApiInterface.java
public interface SecretApiInterface {
#GET("/secret_things")
SecretThing.List getSecretThings(#Header("Authorization") String token)
}
Then you pass the parameters to this interface from your request, something along those lines: (this file would be for example SecretThingRequest.java)
public class SecretThingRequest extends RetrofitSpiceRequest<SecretThing.List, SecretApiInteface>{
private String token;
public SecretThingRequest(String token) {
super(SecretThing.List.class, SecretApiInterface.class);
this.token = token;
}
#Override
public SecretThing.List loadDataFromNetwork() {
SecretApiInterface service = getService();
return service.getSecretThings(Somehow.Magically.getToken());
}
}
Where Somehow.Magically.getToken() is a method call that returns a token, it is up to you where and how you define it.
You can of course have more than one #Header("Blah") String blah annotations in the interface implementation, as in your case!
I found it confusing too, the documentation clearly says it replaces the header, but it DOESN'T!
It is in fact added as with #Headers("hardcoded_string_of_liited_use") annotation
Hope this helps ;)
The accepted answer is for an older version of Retrofit. For future viewers the way to do this with Retrofit 2.0 is using a custom OkHttp client:
OkHttpClient httpClient = new OkHttpClient.Builder()
.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Builder ongoing = chain.request().newBuilder();
ongoing.addHeader("Accept", "application/json;versions=1");
if (isUserLoggedIn()) {
ongoing.addHeader("Authorization", getToken());
}
return chain.proceed(ongoing.build());
}
})
.build();
Retrofit retrofit = new Retrofit.Builder()
// ... extra config
.client(httpClient)
.build();
Hope it helps someone. :)
Retrofit 2.3.0
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
okHttpClientBuilder
.addInterceptor(new Interceptor() {
#Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request.Builder newRequest = request.newBuilder().header("Authorization", accessToken);
return chain.proceed(newRequest.build());
}
});
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(GithubService.BASE_URL)
.client(okHttpClientBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.build();
I am using this to connect to GitHub.

Categories