Dynamiczna kompilacja w Javie

0

Czy w Javie jest możliwa kompilacja i uruchamianie kodu w locie? Jeżeli tak, to w jaki sposób?

Poniższy przykład w C# wyjaśni o co chodzi, chodzi o to, czy w Javie można zrobić to samo.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.IO;

namespace DynaTest
{
    public interface ITest
    {
        string GetMessage();
    }

    class Program
    {
        static void Main(string[] args)
        {
            // Tworzenie kody C#
            StringBuilder CsCode = new StringBuilder();
            CsCode.Append("namespace DynaTest\r\n");
            CsCode.Append("{\r\n");
            CsCode.Append(" public class Test : ITest\r\n");
            CsCode.Append(" {\r\n");
            CsCode.Append("  public string GetMessage()\r\n");
            CsCode.Append("  {\r\n");
            CsCode.Append("   return \"Hello World!\";\r\n");
            CsCode.Append("  }\r\n");
            CsCode.Append(" }\r\n");
            CsCode.Append("}\r\n");

            // Tworzenie obiektu kompilatora i ustawianie parametrow
            CodeDomProvider CodeProvider = CodeDomProvider.CreateProvider("CSharp");
            CompilerParameters CompileParams = new CompilerParameters();
            CompileParams.GenerateInMemory = true;
            CompileParams.ReferencedAssemblies.Add("DynaTest.exe");

            // Kompilacja kodu
            CompilerResults CompiledObject = CodeProvider.CompileAssemblyFromSource(CompileParams, CsCode.ToString());

            // Tworzenie informacji o ewentualnych bledach
            if (CompiledObject.Errors.HasErrors)
            {
                StringBuilder ErrorsMsg = new StringBuilder();
                for (int x = 0; x < CompiledObject.Errors.Count; x++)
                {
                    if (!CompiledObject.Errors[x].IsWarning)
                    {
                        int ErrLn = CompiledObject.Errors[x].Line;
                        int ErrCol = CompiledObject.Errors[x].Column;
                        string ErrMsg = CompiledObject.Errors[x].ErrorText.Replace("'", "''");
                        ErrorsMsg.Append("Ln ").Append(ErrLn.ToString());
                        ErrorsMsg.Append(",Col ").Append(ErrCol.ToString());
                        ErrorsMsg.Append(": ");
                        ErrorsMsg.Append(ErrMsg).Append("\r\n");
                    }
                }
                throw new Exception(ErrorsMsg.ToString());
            }

            // Tworzenie obiektu klasy utworzonej na podstawie skompilowanego kodu
            Assembly CompiledCode = CompiledObject.CompiledAssembly;
            ITest Testobject = (ITest)CompiledCode.CreateInstance("DynaTest.Test");

            // Test dzialania
            Console.Clear();
            Console.WriteLine(Testobject.GetMessage());
            Console.ReadLine();
        }
    }
}
0

Standardowo JRE nie posiada wbudowanego kompilatora Javy, aczkolwiek możesz sobie podpiąć jakąś bibliotekę kompilującą kod Javowy do bajtkodu Javowego i załadować ten bajtkod swoim ClassLoaderem.

Kompilator Javy javac ze standardowego JDK jest napisany w Javie, więc być może da się go dołączyć jako bibliotekę.

Poza tym zwykle nie montuje się kodu explicite tylko manipuluje bajtkodem, a do tego nadaje się np CGLIB.

0

W Javie możesz zrobić to samo o ile masz zainstalowane JDK. Dzięki temu, że dowolny program javowy nie może kompilować nie może działać jako wirus ponieważ nie może łatwo przemycić żadnego kodu (lub jego generatora) w postaci źródłowej po to, żeby tworzyć niewykrywalne mutacje.
Oczywiście nie jest tak, że jak nie ma JDK, to się nie da. Da się (tak jak opisał Wibovit), ale jest to o wiele trudniejsze, więc przeciętny idiota nie jest w stanie tego łatwo wykorzystać do napisania robaka (mi się jeszcze nie udało, więc też chyba się zaliczam do idiotów:)).

W .NET jest to łatwiejsze bo masz wszystko na talerzu i nie musisz admina czy usera pytać o zgodę. Ale jak wiadomo Windows od zawsze jest wirusogenny, więc to żadna nowość.

0

W Javie można ładować taki bajtkod jaki się chce, z tym, że tylko taki który przepuści Security Manager. W .NET też jest Security Manager.

Dołożenie javac do JRE zwiększyłoby instalator powiedzmy o 10%, a nikt praktycznie nie kompiluje kodu Javowego w locie. Zwykle albo się manipuluje bajtkodem za pomocą CGLIB (używa go np Hibernate), albo używa się języków skryptowych, jak Groovy.

Na upartego można jednak dorzucić kompilator Javy do projektu i sobie kompilować.

0

mućka:
A czy to nie wymaga obecnego JDK? Podejrzewam, że wymaga.

0

Z opisu pakiety javax.tools:
These interfaces and classes are required as part of the Java™ Platform, Standard Edition (Java SE), but there is no requirement to provide any tools implementing them.

Super ;d

1 użytkowników online, w tym zalogowanych: 0, gości: 1