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.
Related
I have been trying a ( i hope) simple bit of Android hyperloop code directly within a titanium project (using SDK 7.0.1.GA and hyperloop 3).
var sysProp = require('android.os.SystemProperties');
var serialNumber = sysProp.get("sys.serialnumber", "none");
But when the app is run it reports
Requested module not found:android.os.SystemProperties
I think this maybe due to the fact that when compiling the app (using the cli) it reports
hyperloop:generateSources: Skipping Hyperloop wrapper generation, no usage found ...
I have similar code in a jar and if I use this then it does work, so I am wondering why the hyperloop generation is not being triggered, as I assume that is the issue.
Sorry should have explained better.
This is the jar source that I use, the extraction of the serial number was just an example (I need access to other info manufacturer specific data as well), I wanted to see if I could replicate the JAR functionality using just hyperloop rather that including the JAR file. Guess if it's not broke don't fix it, but was curious to see if it could be done.
So with the feedback from #miga and a bit of trial and error, I have come up with a solution that works really well and will do the method reflection that is required. My new Hyperloop function is
function getData(data){
var result = false;
var Class = require("java.lang.Class");
var String = require("java.lang.String");
var c = Class.forName("android.os.SystemProperties");
var get = c.getMethod("get", String.class, String.class);
result = get.invoke(c, data, "Error");
return result;
}
Where data is a string of the system property I want.
I am using it to extract and match a serial number from a Samsung device that is a System Property call "ril.serialnumber" or "sys.serialnumber". Now I can use the above function to do what I was using the JAR file for. Just thought I'd share in case anyone else needed something similar.
It is because android.os.SystemProperties is not class you can import. Check the android documentation at https://developer.android.com/reference/android/os/package-summary.html
You could use
var build = require('android.os.Build');
console.log(build.SERIAL);
to access the serial number.
I'm trying to use the gitskarios/GithubAndroidSdk to provide my alpha and beta testers a way to view current github issues and report new ones. Here are the steps I've already taken:
Create a GitHub application at LINK.
Add the client info to my application's metadata:
com.alorma.github.sdk.client -> my client's ID
com.alorma.github.sdk.secret -> my client's secret
com.alorma.github.sdk.oauth -> my client's 'Authorization callback URL'
Run this code in my fragment's onCreate:
GithubDeveloperCredentials.init(new MetaDeveloperCredentialsProvider(mParent));
UserReposClient client = new UserReposClient(getActivity(), null);
client.setOnResultCallback(new BaseClient.OnResultCallback<List<Repo>>() {
#Override
public void onResponseOk(List<Repo> repos, Response response) {
Log.d("GitHub", "onResponseOK: " + response);
}
#Override
public void onFail(RetrofitError retrofitError) {
Log.d("GitHub", "onFail: " + retrofitError);
}
});
Log.d("GitHub", "getting repos");
client.execute();
The result is a single log for "getting repos" and no callback.
I've tried removing the call to GithubDeveloperCredentials.init() but that just causes a crash saying that provider is null. I then thought that maybe I didn't have an auth token so I made a call to the RequestTokenClient using null for the second parameter in RequestTokenClient(Context context, String code) but this too never gets a callback or return a null token if executed with executeSync().
UPDATE
I tried using the Personal access tokens (see comments) page to generate an access token then save it into StoreCredentials. When running the execute() command now it appears to be getting a little further but now I'm getting a new error saying:
retrofit.RetrofitError: LoginService.requestToken: HTTP method annotation is required (e.g., #GET, #POST, etc.).
Looking around I found an answer (see comments) saying this might be a proguard issue with the retrofit package. So I added those lines into my app's proguard file but no luck yet.
Can anybody help me? All I want to do is get a list of the open issues.
OK, so I got this working finally though not quite in the best way I wanted. I initially intended each of my Alpha testers to require having their own GitHub account and be added to the project then using their own credentials to obtain an auth token and accessing the bug list. Instead, using the auth token I generated in my update I was able to access the repo. I had to change the proguard to:
-keepattributes *Annotation*,Signature
-keep class retrofit.** { *; }
-keepclasseswithmembers class * {
#retrofit.http.* <methods>; }
(For some reason the *Annotation* and Signature nedded to be on the same line)
Sorry for lame and easy question but I failed to find an answer to it.
Every time I print something to the System.Diagnostics.Debug.WriteLine I have my message tripled:
System.Diagnostics.Debug.WriteLine("test");
Output:
[0:]
test
[0:] test
10-22 19:57:13.981 I/mono-stdout( 1026): test
I'm stick to System.Diagnostic.Debug because I write messages from both UI part (monodroid) and business logic (PCL)
Is there any way to descrease level of debug noise of Xamarin.Android?
Thank you for any suggestions.
Make your own little abstraction. We have the same issue in our project, this little Interface helps:
public interface ILogger
{
void Write(LogLevel level, String tag, String message);
}
Then you have your Loggers for each platform, for example:
public class AndroidLogger: ILogger
{
public void Write(LogLevel level, string tag, string message)
{
Android.Util.Log.WriteLine(ConvertLogLevel(level), tag, message);
}
}
You inject the logger in the iOS/Android project and you can even create fancy logger like e.g. a nice file-logger for iOS:
#if DEBUG
LOG.AddLogger(new TouchFileLogger());
LOG.AddLogger(new ConsoleLogger());
#endif
The LOG-class is static and needs not to know about the implementations, thats why it can be easily used in your shared PCL library.
Hope that helps, despite your problem might be solved by now ;-)
You can use Android.Util.Log instead, this greatly decreases it. It also has different levels of logging which you can filter in logcat.
Info: Log.Info()
Debug: Log.Debug()
Warning: Log.Warn()
Error: Log.Error()
Verbose: Log.Verbose()
and additionally a WriteLine, which does all of the above:
Log.WriteLine()
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
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.