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);
        }
Exemple #2
0
        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);
        }
Exemple #6
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();
            }
        }