I'm attempting to follow the example tutorial at https://developers.google.com/eclipse/docs/endpoints-addentities and I'm stuck figuring out how to get the GameEndpoint.Builder class to generate within Eclipse.
After following this and generating the cloud endpoints as described, I have a GameEndpoint class created, but there is no GameEndpoint.Builder class. So obviously I have this error
GameEndpoint.Builder cannot be resolved to a type
I'm stumped at this point. How do I generate the GameEndpoint.Builder class within Eclipse, or what would prevent it?
Code
public class NewGameTask extends AsyncTask<Context, Integer, Long> {
protected Long doInBackground(Context... contexts) {
GameEndpoint.Builder endpointBuilder = new GameEndpoint.Builder(
AndroidHttp.newCompatibleTransport(), new JacksonFactory(),
new HttpRequestInitializer() {
public void initialize(HttpRequest httpRequest) {
}
});
GameEndpoint endpoint = CloudEndpointUtils.updateBuilder(
endpointBuilder).build();
try {
Game game = new Game();
game.setStart(Calendar.getInstance());
Game result = endpoint.insertGame(game);
} catch (IOException e) {
e.printStackTrace();
}
return (long) 0;
}
}
I figured out my issue after watching this video from Google I/O 2013 which is using Android Studio, but it was the same thing as Eclipse mostly.
My mistake in following https://developers.google.com/eclipse/docs/endpoints-addentities was that you need to put your entity class into the MyApp-AppEngine project and NOT your MyApp project.
That was the source of confusion. In case it helps those in the future, here is a short breakdown of what I did.
Put the Entity class you want to add to App Engine into your MyApp-AppEngine project.
Right click your class and go to Google > Generate Cloud Endpoint Client Library
Right click your MyApp-AppEngine project and go to Google > Generate Cloud Enpoint Client Library
New references will be made in your MyApp project which you reference in your project for usage.
Note This answer is based on Android Studio, but am sure it's pretty much the same as Eclipse.
I also had this issue but later found the cause.Turns out I was importing the Endpoint class I generated instead of the endpoint Api package. Let me be clear.When you add the endpoint module to your project, you get the MyBean and MyEndpoint classes in the endpoint package. If you take a look at the guide to connecting your client to your backend, the EndpointsAsyncTask class uses:
private static MyApi myApiService = null;
Note how it uses MyApi instead of MyBean Now I was wondering where it got that from but I just have to take a look at my backend libraries:
The library marked 1 is the library first added to your project when you follow the guide previously mentioned. When I added a new class Student and autogenerated the cloud endpoint class, the second library was also added.
Long, boring story short; It is this library you should be importing and not the class.
import com.package-name.backend.studentApi.StudentApi;
and then using:
private static StudentApi myApiService = null;
...
StudentApi.Builder builder = new StudentApi.Builder(...)
instead of:
import com.package-name.backend.StudentEndpoint;
...
private static StudentEndpoint myApiService = null;
StudentEndpoint.Builder builder = new StudentEndpoint.Builder(...)
I got the same problem in Android Studio. I generated my Endpoint class from my entity java bean but when creating the AsyncTask, now way to get the Builder.
Actually (if I take a Game java bean like you) the Builder is not depending on the GameEndPoint but on the generated GameApi class.
In other words, I had to add these two imports in the AsyncTask class:
import com.examplepackage.backend.gameApi.GameApi;
import com.examplepackage.backend.gameApi.model.Game;
while the Game java bean that you wrote and the generated GameEndpoint are under package com.examplepackage.backend
Related
So I'm trying to use an API from a website but inorder to use it i'll have to send my login informaton. The documentation shows me a python example on how to login.
R = requests.post('http://nova.astrometry.net/api/login', data={'request-json':
json.dumps({"apikey": "XXXXXXXX"})})
print(R.text)
So what is the Kotlin equivalent of the above code ? In the websites documentation it states
"Note the request-json=VALUE: we’re not sending raw JSON, we’re sending the JSON-encoded string as though it were a text field called request-json."
I have attempted to use Android Volley but im not entirely sure how to use it.
private fun plateSolve(){
val json=JSONObject(map).toString()
Log.d(TAG,"URL:$url")
Log.d(TAG,"Hashmap:$json")
JSONObject(map).toString()
val jsonObjectRequest = JsonObjectRequest(
Request.Method.POST, url, null,
{ response ->
try {
Log.d(TAG,"POST Response: %s".format(response.toString()))
}catch (e:Exception){
Log.d(TAG,"Exception: $e")
}
},
{ error ->
// TODO: Handle error
Log.d(TAG,"There Was an Error")
error.stackTraceToString()
}
)
// Access the RequestQueue through your singleton class.
VolleySingleton.instance?.addToRequestQueue(jsonObjectRequest)
}
Thanks in advance
it's not recommended to use volley anymore for android please use retrofit as its google's recommended library,the answer for your question is too big so i will write some checkpoints to do and also i have shared a simple working example with retrofit one of my own projects on github , hopefully this helps you
retrofit link - https://square.github.io/retrofit/
Insert library files in gradle
create response classes
create retrofit api class
4.create interface class with api calls
Github project with app using retrofit for api calls
https://github.com/zaidzak9/NewsApp
I need to implement SSL Certificate Pinning in my react native application.
I know very little about SSL/TLS let alone pinning.
I am also not a native mobile developer, though I know Java and learned Objective-C on this project enough to get around.
I started searching for how to execute this task.
Doesn't React Native already implement this?
No, My initial search lead me to this proposal which has received no activity since August 2nd 2016.
From it I learned that react-native uses OkHttp which does support Pinning, but I wouldn't be able to pull it off from Javascript, which is not really a requirement but a plus.
Implement it in Javascript.
While react seems like it uses the nodejs runtime, it is more like a browser than node, meaning it does not support all native modules, specifically the https module, for which I had implemented certificate pinning following this article. Thus could not carry it into react native.
I tried using rn-nodeify but the modules didn't work. This has been true since RN 0.33 to RN 0.35 which I'm currently on.
Implement using phonegap plugin
I thought of using a phongape-plugin however since I have a dependency on libraries that require react 0.32+ I can't use react-native-cordova-plugin
Just do it natively
While I'm not a native app developer I can always take a crack at it, only a matter of time.
Android has certificate pinning
I learned that android supports SSL Pinning however was unsuccessful as it seems that this approach does not work Prior to Android 7. As well as only working for android.
The bottom line
I have exhausted several directions and will continue to pursue more native implementation, maybe figure out how to configure OkHttp and RNNetworking then maybe bridging back to react-native.
But is there already any implementations or guide for IOS and android?
After exhausting the current spectrum of available options from Javascript I decided to simply implement certificate pinning natively it all seems so simple now that I'm done.
Skip to headers titled Android Solution and IOS Solution if you don't want to read through the process of reaching the solution.
Android
Following Kudo's recommendation I thought out to implement pinning using okhttp3.
client = new OkHttpClient.Builder()
.certificatePinner(new CertificatePinner.Builder()
.add("publicobject.com", "sha1/DmxUShsZuNiqPQsX2Oi9uv2sCnw=")
.add("publicobject.com", "sha1/SXxoaOSEzPC6BgGmxAt/EAcsajw=")
.add("publicobject.com", "sha1/blhOM3W9V/bVQhsWAcLYwPU6n24=")
.add("publicobject.com", "sha1/T5x9IXmcrQ7YuQxXnxoCmeeQ84c=")
.build())
.build();
I first started by learning how to create a native android bridge with react nativecreating a toast module. I then extended it with a method for sending a simple request
#ReactMethod
public void showURL(String url, int duration) {
try {
Request request = new Request.Builder()
.url(url)
.build();
Response response = client.newCall(request).execute();
Toast.makeText(getReactApplicationContext(), response.body().string(), duration).show();
} catch (IOException e) {
Toast.makeText(getReactApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
Succeeding in sending a request I then turned to sending a request pinned.
I used these packages in my file
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.CertificatePinner;
import java.io.IOException;
import java.util.Map;
import java.util.HashMap;
Kudo's approach wasn't clear on where I would get the public keys or how to generate them. luckily okhttp3 docs in addition to providing a clear demonstration of how to use the CertificatePinner stated that to get the public keys all I would need to do is send a request with an incorrect pin, and the correct pins will appear in the error message.
After taking a moment to realise that OkHttpClent.Builder() can be chained and I can include the CertificatePinner before the build, unlike the misleading example in Kudo's proposal (probably and older version) I came up with this method.
#ReactMethod
public void getKeyChainForHost(String hostname, Callback errorCallbackContainingCorrectKeys,
Callback successCallback) {
try {
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add(hostname, "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.build();
OkHttpClient client = (new OkHttpClient.Builder()).certificatePinner(certificatePinner).build();
Request request = new Request.Builder()
.url("https://" + hostname)
.build();
Response response =client.newCall(request).execute();
successCallback.invoke(response.body().string());
} catch (Exception e) {
errorCallbackContainingCorrectKeys.invoke(e.getMessage());
}
}
Then replacing the public keychains I got in the error yielded back the page's body, indicating I had made a successful request, I change one letter of the key to make sure it was working and I knew I was on track.
I finally had this method in my ToastModule.java file
#ReactMethod
public void getKeyChainForHost(String hostname, Callback errorCallbackContainingCorrectKeys,
Callback successCallback) {
try {
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add(hostname, "sha256/+Jg+cke8HLJNzDJB4qc1Aus14rNb6o+N3IrsZgZKXNQ=")
.add(hostname, "sha256/aR6DUqN8qK4HQGhBpcDLVnkRAvOHH1behpQUU1Xl7fE=")
.add(hostname, "sha256/HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=")
.build();
OkHttpClient client = (new OkHttpClient.Builder()).certificatePinner(certificatePinner).build();
Request request = new Request.Builder()
.url("https://" + hostname)
.build();
Response response =client.newCall(request).execute();
successCallback.invoke(response.body().string());
} catch (Exception e) {
errorCallbackContainingCorrectKeys.invoke(e.getMessage());
}
}
Android Solution Extending React Native's OkHttpClient
Having figured out how to send pinned http request was good, now I can use the method I created, but ideally I thought it would be best to extend the existing client, so as to immediately gain the benefit of implementing.
This solution is valid as of RN0.35 and I don't know how it will fair in the future.
While looking into ways of extending the OkHttpClient for RN I came across this article explaining how to add TLS 1.2 support through replacing the SSLSocketFactory.
reading it I learned react uses an OkHttpClientProvider for creating the OkHttpClient instance used by the XMLHttpRequest Object and therefore if we replace that instance we would apply pinning to all the app.
I added a file called OkHttpCertPin.java to my android/app/src/main/java/com/dreidev folder
package com.dreidev;
import android.util.Log;
import com.facebook.react.modules.network.OkHttpClientProvider;
import com.facebook.react.modules.network.ReactCookieJarContainer;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.CertificatePinner;
public class OkHttpCertPin {
private static String hostname = "*.efghermes.com";
private static final String TAG = "OkHttpCertPin";
public static OkHttpClient extend(OkHttpClient currentClient){
try {
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add(hostname, "sha256/+Jg+cke8HLJNzDJB4qc1Aus14rNb6o+N3IrsZgZKXNQ=")
.add(hostname, "sha256/aR6DUqN8qK4HQGhBpcDLVnkRAvOHH1behpQUU1Xl7fE=")
.add(hostname, "sha256/HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=")
.build();
Log.d(TAG, "extending client");
return currentClient.newBuilder().certificatePinner(certificatePinner).build();
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
return currentClient;
}
}
This package has a method extend which takes an existing OkHttpClient and rebuilds it adding the certificatePinner and returns the newly built instance.
I then modified my MainActivity.java file following this answer's advice by adding the following methods
.
.
.
import com.facebook.react.ReactActivity;
import android.os.Bundle;
import com.dreidev.OkHttpCertPin;
import com.facebook.react.modules.network.OkHttpClientProvider;
import okhttp3.OkHttpClient;
public class MainActivity extends ReactActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
rebuildOkHtttp();
}
private void rebuildOkHtttp() {
OkHttpClient currentClient = OkHttpClientProvider.getOkHttpClient();
OkHttpClient replacementClient = OkHttpCertPin.extend(currentClient);
OkHttpClientProvider.replaceOkHttpClient(replacementClient);
}
.
.
.
This solution was carried out in favor of completely reimplementing the OkHttpClientProvider createClient method, as inspecting the provider I realized that the master version had implemented TLS 1.2 support but was not yet an available option for me to use, and so rebuilding was found to be the best means of extending the client. I'm wondering how this approach will fair as I upgrade but for now it works well.
Update It seems that starting 0.43 this trick no longer works. For timebound reasons I will freeze my project at 0.42 for now, until the reason for why rebuilding stopped working is clear.
Solution IOS
For IOS I had thought I would need to follow a similar method, again starting with Kudo's proposal as my lead.
Inspecting the RCTNetwork module I learned that NSURLConnection was used, so instead of trying to create a completely new module with AFNetworking as suggested in the proposal I discovered TrustKit
following its Getting Started Guide I simply added
pod 'TrustKit'
to my podfile and ran pod install
the GettingStartedGuide explained how I can configure this pod from my pList.file but preferring to use code than configuration files I added the following lines to my AppDelegate.m file
.
.
.
#import <TrustKit/TrustKit.h>
.
.
.
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Initialize TrustKit
NSDictionary *trustKitConfig =
#{
// Auto-swizzle NSURLSession delegates to add pinning validation
kTSKSwizzleNetworkDelegates: #YES,
kTSKPinnedDomains: #{
// Pin invalid SPKI hashes to *.yahoo.com to demonstrate pinning failures
#"efghermes.com" : #{
kTSKEnforcePinning:#YES,
kTSKIncludeSubdomains:#YES,
kTSKPublicKeyAlgorithms : #[kTSKAlgorithmRsa2048],
// Wrong SPKI hashes to demonstrate pinning failure
kTSKPublicKeyHashes : #[
#"+Jg+cke8HLJNzDJB4qc1Aus14rNb6o+N3IrsZgZKXNQ=",
#"aR6DUqN8qK4HQGhBpcDLVnkRAvOHH1behpQUU1Xl7fE=",
#"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY="
],
// Send reports for pinning failures
// Email info#datatheorem.com if you need a free dashboard to see your App's reports
kTSKReportUris: #[#"https://overmind.datatheorem.com/trustkit/report"]
},
}
};
[TrustKit initializeWithConfiguration:trustKitConfig];
.
.
.
I got the public key hashes from my android implementation and it just worked (the version of TrustKit I received in my pods is 1.3.2)
I was glad IOS turned out to be a breath
As a side note TrustKit warned that it's Auto-swizzle won't work if the NSURLSession and Connection are already swizzled. that said it seems to be working well so far.
Conclusion
This answer presents the solution for both Android and IOS, given I was able to implement this in native code.
One possible improvement may be to implement a common platform module where setting public keys and configuring the Network providers of both android and IOS can be managed in javascript.
Kudo's proposal mentioned simply adding the public keys to the js bundle may however expose a vulnerability, where somehow the bundle file can be replaced.
I don't know how that attack vector can function, but certainly the extra step of signing the bundle.js as proposed may protect the js bundle.
Another approach may be to simply encode the js bundle into a 64 bit string and include it in the native code directly as mentioned in this issue's conversation. This approach has the benefit of obfuscating as well hardwiring the js bundle into the app, making it inaccessible for attackers or so I think.
If you read this far I hope I enlightened you on your quest for fixing your bug and wish you enjoy a sunny day.
You can use this lib https://github.com/nlt2390/react-native-pinning-ssl
It verifies SSL connection using SHA1 keys, not certificates.
I am trying to figure out how to add ACRA in my test project in Android Studio.
Following this article (which explains how to do it in Eclipse) https://github.com/ACRA/acra/wiki/BasicSetup, I have passed all so far up to the point where is explains to annotate your Application class with #ReportsCrashes. In this part, I dont know what to put as formUri.
I am just creating my own test app (API22 Lollipop) and trying to add ACRA support to it. I don't have any server, it is just a simple Android app.
import org.acra.*;
import org.acra.annotation.*;
#ReportsCrashes(
formKey = "", // This is required for backward compatibility but not used
formUri = "http://www.backendofyourchoice.com/reportpath"
)
public class MyApplication extends Application {
}
What do I put as the formUri?
Can you explain what formUri is for and how it works as I am new to dev?
Please explain
Thanks,
formUri points to your crash report server.
There are many to choose from, commercial and free.
The ACRA wiki lists several.
ACRAlyzer is one, but you will need to host it yourself.
Read about Acralyzer: https://github.com/ACRA/acralyzer/wiki/setup
It is simple backend for ACRA reports.
#ReportsCrashes(
formUri = "https://[your.couchdb.host]/acra-[yourappname]/_design/acra-storage/_update/report",
formUriBasicAuthLogin="[reporteruser]",
formUriBasicAuthPassword="[reporterpassword]",
reportType = org.acra.sender.HttpSender.Type.JSON,
httpMethod = org.acra.sender.HttpSender.Method.PUT,
....
)
public class [YourApplication] extends Application {
#Override
public final void onCreate() {
super.onCreate();
ACRA.init(this);
}
There you will find the usage of the Acralyzer user interface: https://github.com/ACRA/acralyzer/wiki/usermanual
I am using Log4j to log data in my android application. I have configured the log4j with the help of the following class, but the log files are not getting created.
console logging is enabled, maxfilesize and maxbackupsize are also good. please let me know what i am missing here.
public class ConfigureLog4J {
static LogConfigurator logConfigurator = new LogConfigurator();
private static final int maxFileSize = 1024 * 5; // 100KB
public static final int maxBackupSize = 2; // 2 backup files
public static final String LOG_FILE_NAME = "bitzer.log";
private static HashMap<Integer, Level> logLevelMap = new HashMap<Integer, Level>();
static {
logLevelMap.put(0, Level.OFF);
logLevelMap.put(1, Level.ERROR);
logLevelMap.put(2, Level.INFO);
logLevelMap.put(3, Level.WARN);
logLevelMap.put(4, Level.DEBUG);
logLevelMap.put(5, Level.ALL);
}
public static void startWithLogLevel(int logLevel) {
logConfigurator.setFileName(getLogFileName());
logConfigurator.setRootLevel(getLevelFromInt(logLevel));
logConfigurator.setUseFileAppender(true);
logConfigurator.setUseLogCatAppender(isConsoleLoggingEnabled());
logConfigurator.setMaxFileSize(getMaxFileSize());
logConfigurator.setMaxBackupSize(maxBackupSize);
// Set log level of a specific logger
// logConfigurator.setLevel("org.apache", Level.ERROR);
logConfigurator.setResetConfiguration(true);
logConfigurator.configure();
}
private static long getMaxFileSize() {
return CompanySettings.getInstance().getValueAsInteger(R.string.max_log_size);
}
private static boolean isConsoleLoggingEnabled() {
return CompanySettings.getInstance().getValueAsBoolean(R.string.consoleLoggingEnabled);
}
private static Level getLevelFromInt(int newLogLevel) {
return logLevelMap.get(newLogLevel);
}
public static String getLogsDirectory() {
if(AppData.getInstance().getContext()!=null)
{ String packageName = AppData.getInstance().getContext().getPackageName();
System.out.println("sundeep package name is not null and it's"+packageName);
return "data/data/" + packageName + "/logs/";
}
return null;
}
public static String getLogFileName() {
return getLogsDirectory() + LOG_FILE_NAME;
}
}
SLF4J Overview
I highly recommend you use SLF4J, which is log4j's "older brother" of sorts; the same developers who made log4j made SLF4J to address the shortcomings of log4j.
The difference is, whereas log4j is a full-fledged logging framework, SLF4J is a facade which you use directly in your Java code. The facade aspect allows you to plugin a concrete logging implementation — such as log4j, logback, Android's Log utility, etc. — at runtime.
It allows you to write code that can be used between different projects without having to go through your code and convert your logging statements to use the target project's logging framework. If you have several thousand lines of code which use log4j, but the target you're importing them into uses Apache Commons logging, you'll soon find yourself with a headache if you manually make the changes... even with the assistance of a capable IDE.
Using log4j in Android
There's a great Android library for logging to log4j — as well as many other logging frameworks as well — called android-logging-log4j. Check out the very excellent section on "Using log4j over slf4j", which is the route I take in my Android projects.
Examples from my own projects
Here are some examples from my own projects, such as my Awnry News & Weather app. (Yeah, shameless plug :P)
Required JARs on classpath
Basically these are the JARs I'll typically have in my project's classpath (version numbers vary as new releases come about, of course).
android-logging-log4j-1.0.3.jar
log4j-1.2.17.jar
slf4j-api-1.7.6.jar
slf4j-log4j12-1.7.6.jar
Instantiating a class's logger
And here's how I instantiate my general logger in each of my classes that require logging:
package com.awnry.android.naw;
...
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...
public class NawApplication extends Application
{
private static final Logger log = LoggerFactory.getLogger(NawApplication.class);
As you can see, I'm only referencing SLF4J's Logger and LoggerFactory interfaces, even though the actual logging may eventually be accomplished using log4j or Android's Log.
That's the beauty of SLF4J's facade design: You aren't tied down to any specific logging implementation/framework; you can change your mind in the future without having to change a line of your code. If you're using log4j over SLF4J now, but in the future you want to use the Apache Commons Logging framework all you have to do is switch out the SLF4J-to-log4j bridge to a SLF4J-to-ACL bridge, and none of your Java code will be any wiser as it only calls SLF4J interfaces. The time-honored adage to code to an interface, not an implementation holds true once again, and SLF4J is a superb example of that.
Configuring the Android app's logging
In my Application.onCreate() method, I configure my logging like this:
#Override
public void onCreate()
{
...
String logFile = getFilesDir().getAbsolutePath() + File.separator + "logs" + File.separator + "debug.log";
log.info("Application log file: " + logFile);
LogConfigurator logConfigurator = new LogConfigurator(logFile, Level.TRACE);
logConfigurator.configure();
...
}
This part is actually optional, I believe. In my case I do this because I use the ACRA library to help catch unexpected program crashes and report the details back to me for debugging, so you might not need to define your android-logging-log4j's LogConfigurator as I do here.
Why you are using log4j.
There are efficient Log utility is available specially designed for android.
Use LogCat. Its very simple to use and standard way of putting log in your android app.
Could you guys please help me why I'm having this exception?
I extracted RequestFactory proxies and context interfaces into separate jar so I can use it both in GWT client and Android client (details are here)
Unfortunately RF throws an exception on the server in very first call. The exception is:
com.google.web.bindery.requestfactory.server.UnexpectedException: No RequestContext for operation LPZEK7DlYkoG1$NQ5MjHlmuRChk=
at com.google.web.bindery.requestfactory.server.ServiceLayerDecorator.die(ServiceLayerDecorator.java:216)
at com.google.web.bindery.requestfactory.server.ResolverServiceLayer.resolveRequestContext(ResolverServiceLayer.java:154)
Below is my factory interface. As you can see I had to replace Service annotations with ServiceName because I didn't want to compile all custom locators with Guice injections to jar that will go on mobile devices.
public interface AdminRequestFactory extends RequestFactory
{
// #Service(value = UserServiceDao.class, locator = InjectingServiceLocator.class)
#ServiceName(value = "com.blah.courierApp.server.dao.UserServiceDao", locator = "com.blah.courierApp.server.inject.InjectingServiceLocator")
public interface GaeUserServiceContext extends RequestContext
{
public Request<String> createLogoutURL(String destinationURL);
public Request<GaeUser> getCurrentUser();
}
// #Service(value = OrderDao.class, locator = InjectingServiceLocator.class)
#ServiceName(value = "com.blah.courierApp.server.dao.OrderDao", locator = "com.blah.courierApp.server.inject.InjectingServiceLocator")
public interface OrderRequestContext extends RequestContext
{
Request<List<OrderProxy>> listAll();
Request<Void> delete(Long id);
Request<Void> createOrder(OrderProxy order);
Request<OrderProxy> findOrderById(long id);
Request<Void> updateOrderState(long id, StateType newStateType);
}
GaeUserServiceContext contextUserService();
OrderRequestContext contextOrder();
}
When I compiled it RF Annotation Tool gave following warning:
Cannot fully validate context since domain type com.blah.courierApp.server.dao.UserServiceDao is not available.
You must run the ValidationTool as part of your server build process.
Add #SuppressWarnings("requestfactory") to dismiss.
So when the exception thrown under the debugger on the server I see that instance of com.google.web.bindery.requestfactory.vm.impl.Deobfuscator has empty operationData field which is being initialized by DeobfuscatorBuilder class that was generated by RequestFactory annotation tool.
So... I decompiled that class and found this:
public final class AdminRequestFactoryDeobfuscatorBuilder extends Deobfuscator.Builder
{
public AdminRequestFactoryDeobfuscatorBuilder()
{
withRawTypeToken("w1Qg$YHpDaNcHrR5HZ$23y518nA=", "com.google.web.bindery.requestfactory.shared.EntityProxy");
withRawTypeToken("8KVVbwaaAtl6KgQNlOTsLCp9TIU=", "com.google.web.bindery.requestfactory.shared.ValueProxy");
withRawTypeToken("FXHD5YU0TiUl3uBaepdkYaowx9k=", "com.google.web.bindery.requestfactory.shared.BaseProxy");
withRawTypeToken("5vjE9LUy$l0uvi4kMYpS3JA1WEE=", "com.blah.shared.model.GaeUser");
withRawTypeToken("8KVVbwaaAtl6KgQNlOTsLCp9TIU=", "com.google.web.bindery.requestfactory.shared.ValueProxy");
withRawTypeToken("5a7OV4PSV$1xemsooKLfEQ4g5yY=", "com.blah.shared.proxies.OrderProxy");
withRawTypeToken("neR_xIhE5oZsc0HbnkAMa8A88yw=", "com.blah.shared.proxies.OrderStateProxy");
withRawTypeToken("t6gMQWDROJnYvqYhNURV8pd$sn4=", "com.blah.shared.proxies.OrganizationProxy");
withRawTypeToken("1o45xgS$5bIkBKF4wlR8oMw_FSo=", "com.blah.shared.proxies.PersonProxy");
withRawTypeToken("FXHD5YU0TiUl3uBaepdkYaowx9k=", "com.google.web.bindery.requestfactory.shared.BaseProxy");
}
}
It didn't generated tokens for factory. Therefore there are no calls to Deobfuscator.Builder.withOperation because of which my server can't find context when calls comes from the client.
Questions are:
Why doesn't RequestFactory Annotation Tool generate tokens for factory (operations) ?
How can I fix it ?
Well, it was pretty tricky... But debugging in RF Annotation Tool helped :)
Turns out you have to have domain classes that you refer to in #ServiceName in classpath of RF Annotation Processor. It creates chicken-and-egg problem. You have to compile SharedClasses module to compile main module but you have to compile domain classes from main module to compile SharedClasses module.
Here is what I did:
Disabled RF annotation processing for SharedClasses module.
In RF annotation processor of main module I explicitly specified RF factory that has to be processed using parameter rootOverride = com.blah.shared.factories.AdminRequestFactory
It sucks that I have hardcoded full qualified class name in project settings though.
If you guys know more elegant method please let me know.
I too hit the same problem. Basically I have 3 GWT modules 1. Main module and in the second module I have the requestFactory, server domain classes and the client side proxy values. I am pretty much sure that your solution is what I need to put in place. However I am confused how to specify the rootOverride in the maven build phase. Any pointers in the structure of pom.xml would be immensely helpful.