public void JavaTypesAreMigratedAfterJetifierWithIntermediate() { var migratedAar = Utils.GetTempFilename(); var jetifier = new Jetifier(); jetifier.UseIntermediateFile = true; var result = jetifier.Jetify(SupportAar, migratedAar); Assert.True(result); var jar = ReadAarEntry(migratedAar, "classes.jar"); var classPath = new ClassPath(); classPath.Load(jar); var packages = classPath.GetPackages(); Assert.True(packages.Count > 0); Assert.Equal("com.xamarin.aarxercise", packages.Keys.FirstOrDefault()); var classes = packages["com.xamarin.aarxercise"]; var simpleFragment = classes.FirstOrDefault(c => c.ThisClass.Name.Value == "com/xamarin/aarxercise/SimpleFragment"); Assert.Equal("androidx/fragment/app/Fragment", simpleFragment.SuperClass.Name.Value); }
public static void Main(string [] args) { bool skipChanged = false; if (args.Length > 2) { if (args[0] == "--no-changed") { skipChanged = true; args = args.Skip(1).ToArray(); } } if (args.Length != 2) { PrintUsage(); return; } var jar1 = new ClassPath(args [0]); var jar2 = new ClassPath(args [1]); var packages1 = jar1.GetPackages(); var packages2 = jar2.GetPackages(); var commonPackages = HashSetDiffing(packages1, packages2, p => p.Key, (rt, items) => ReportConsole("packages", rt, items)); foreach (var package in commonPackages) { var commonTypes = HashSetDiffing(package.Item1.Value, package.Item2.Value, c => c.ThisClass.Name.Value, (rt, items) => ReportConsole("classes in package " + package.Item1.Key, rt, items)); foreach (var type in commonTypes) { Func <MethodInfo, bool> noSpecialMethods = mn => mn.Name.IndexOf("$", StringComparison.Ordinal) == -1; var commonMethods = HashSetDiffing(type.Item1.Methods.Where(noSpecialMethods), type.Item2.Methods.Where(noSpecialMethods), m => m.Name + " :: " + m.Descriptor, (rt, items) => ReportConsole("methods in class " + type.Item1.ThisClass.Name.Value, rt, items)); if (type.Item1.IsEnum) { continue; } if (!skipChanged) { var differingMethods = GetMethodsWithDifferingBodies(commonMethods).ToList(); if (differingMethods.Any()) { ReportConsole("methods in type " + type.Item1.ThisClass.Name.Value, ReportType.Changed, differingMethods); } } } } }
private void DoSearch(string artifact, ClassPath classPath, string javaClass) { foreach (var package in classPath.GetPackages()) { var classFiles = package.Value; foreach (var classFile in classFiles) { var thisClass = classFile.ThisClass; if (thisClass.Name.Value.Contains(javaClass)) { Console.WriteLine($"{thisClass.Name.Value}: {artifact}"); } } } }
//[Fact] public async Task JetifierWrapperMigratesFacebookAar() { var facebookFilename = "facebook-android-sdk"; var facebookVersion = "4.40.0"; var facebookFullName = $"{facebookFilename}-{facebookVersion}"; var facebookTestUrl = $"https://origincache.facebook.com/developers/resources/?id={facebookFullName}.zip"; var workspace = Utils.GetTempFilename(); Directory.CreateDirectory(workspace); // download facebook var facebookZip = Path.Combine(workspace, "facebook.zip"); await Utils.DownloadFileAsync(facebookTestUrl, facebookZip); ZipFile.ExtractToDirectory(facebookZip, workspace); // run jetifier var aarFiles = Directory.GetFiles(workspace, "*.aar", SearchOption.AllDirectories); var pairs = aarFiles.Select(f => new MigrationPair(f, Path.ChangeExtension(f, "jetified.aar"))).ToArray(); var jetifier = new Jetifier(); var result = jetifier.Jetify(pairs); Assert.True(result); // read the classes var commonAar = pairs.FirstOrDefault(pair => Path.GetFileNameWithoutExtension(pair.Source) == "facebook-common"); var jar = ReadAarEntry(commonAar.Destination, "classes.jar"); var classPath = new ClassPath(); classPath.Load(jar); var packages = classPath.GetPackages(); // read the type var classes = packages["com.facebook"]; var activity = classes.FirstOrDefault(c => c.ThisClass.Name.Value == "com/facebook/FacebookActivity"); // read the layout var migratedLayout = ReadAarEntry(commonAar.Destination, "res/layout/com_facebook_device_auth_dialog_fragment.xml"); // check Assert.Equal("androidx/fragment/app/FragmentActivity", activity.SuperClass.Name.Value); Assert.Equal( "androidx.cardview.widget.CardView", XDocument.Load(migratedLayout).Root.Name.LocalName); }
public void CanReadJarFileAfterMigration() { var migratedAar = Utils.GetTempFilename(); var jetifier = new Jetifier(); var result = jetifier.Jetify(SupportAar, migratedAar); Assert.True(result); var jar = ReadAarEntry(migratedAar, "classes.jar"); var classPath = new ClassPath(); classPath.Load(jar); var packages = classPath.GetPackages(); Assert.True(packages.Count > 0); Assert.Equal("com.xamarin.aarxercise", packages.Keys.FirstOrDefault()); var classes = packages["com.xamarin.aarxercise"]; Assert.True(classes.Count > 0); }
public static void Main(string[] args) { bool dump = false; bool help = false; bool docsType = false; int verbosity = 0; bool autorename = false; bool no_streams = false; var outputFile = (string)null; string platform = null; var docsPaths = new List <string> (); var p = new OptionSet() { "usage: class-dump [-dump] FILES", "", "View the metadata contents of a Java .class or .jar file.", "", "Options:", { "dump", "Dump out .class metadata, including constant pool.\nDefault is XML output.", v => dump = v != null }, { "o=", "Write output to {PATH}.", v => outputFile = v }, { "docspath=", "Documentation {PATH} for parameter fixup", doc => docsPaths.Add(doc) }, { "parameter-names=", "{PATH} for Java method parameter name information", doc => docsPaths.Add(doc) }, { "docstype=", "OBSOLETE: Previously used to specify a doc type (now auto detected).", t => docsType = t != null }, { "v|verbose:", "See stack traces on error.", (int?v) => verbosity = v.HasValue ? v.Value : verbosity + 1 }, { "autorename", "Renames parameter names in the interfaces by derived classes.", v => autorename = v != null }, { "ignore-stream-api", "Ignore all apis from stream api.", v => no_streams = v != null }, { "platform=", "(Internal use only) specify Android framework platform ID", v => platform = v }, { "h|?|help", "Show this message and exit.", v => help = v != null }, }; var files = p.Parse(args); if (help) { p.WriteOptionDescriptions(Console.Out); return; } if (docsType) { Console.WriteLine("class-parse: --docstype is obsolete and no longer a valid option."); } var output = outputFile == null ? Console.Out : (TextWriter) new StreamWriter(outputFile, append: false, encoding: new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); Log.OnLog = (t, v, m, a) => { Console.Error.WriteLine(m, a); }; var classPath = new ClassPath() { ApiSource = "class-parse", AndroidFrameworkPlatform = platform, DocumentationPaths = docsPaths.Count == 0 ? null : docsPaths, AutoRename = autorename }; foreach (var file in files) { try { if (dump) { DumpClassFile(file, output); continue; } DumpFileToXml(classPath, file); } catch (Exception e) { Console.Error.WriteLine("class-parse: Unable to read file '{0}': {1}", file, verbosity == 0 ? e.Message : e.ToString()); Environment.ExitCode = 1; } } if (no_streams) { bool IsStreamApi(TypeInfo m) { return(m.BinaryName.StartsWith("Ljava/util/stream/") || m.BinaryName.StartsWith("Ljava/util/function/")); } foreach (var klass in classPath.GetPackages().Values.SelectMany(a => a)) { var streamApis = klass.Methods.Where(m => IsStreamApi(m.ReturnType) || m.GetParameters().Any(a => IsStreamApi(a.Type))).ToList(); foreach (var item in streamApis) { klass.Methods.Remove(item); } } } if (!dump) { classPath.SaveXmlDescription(output); } if (outputFile != null) { output.Close(); } }