Страницы

Поиск по вопросам

Показаны сообщения с ярлыком рефлексия. Показать все сообщения
Показаны сообщения с ярлыком рефлексия. Показать все сообщения

суббота, 11 апреля 2020 г.

Система плагинов

#c_sharp #plugin #рефлексия

                    
Захотелось научиться работать с отражением и вот этим всем.
Начал с простенького, решил написать подключаемый плагин, который автоматически подгрузится
из именной папки.

Что бы не мучиться с отражением методов и прочей нечистью на ум конечно же приходит
наследование и полиморфизм.
То есть мне нужен какой-то базовый класс с начальным функционалом от которого будут
наследоваться все другие плагины.

То есть нужно сделать отдельную библиотеку с апи, которую будут использовать обе
стороны (программа и плагин).

public interface IPlugin
{
    void Loaded();
}


Вот такой класс придумал в этой библиотеке.
Теперь я могу спокойно ее подключать к плагину и наследоваться.

public class Test : IPlugin
{
    #region Implementation of IPlugin

    public void Loaded() => Console.WriteLine( "Hello World" );

    #endregion
}


Вот у меня уже две библиотеки, одна с моим апи, другая его использует.
Теперь мне нужно как-то загрузить сборку с плагином и использовать его методы.
Вот тут мне и нужна помощь.

Так как библиотека плагина использует другую библиотеку с апи, я не смогу ее так
просто загрузить, так как выскочит ошибка мол либе не хватает референсов. Как правильно
загрузить плагин указав что сборка которая ему нужна уже загружена в программу?

Вот код которым я пытаюсь что-то наколдовать:

private static void Main ( string[] args )
    {
        var pluginsPath = $"{Directory.GetCurrentDirectory()}\\Plugins";
        var files = Directory.GetFiles( pluginsPath , "*.dll" );

        foreach ( var file in files )
        {
            Console.WriteLine( $"Trying load: {file}" );
            Assembly assembly;

            try { assembly = Assembly.Load( file ); }
            catch ( Exception ex )
            {
                Console.WriteLine( ex.Message );
                continue;
            }

            var types =
                assembly.GetTypes().Where( type => type.IsClass && type.GetInterface(
nameof( IPlugin ) ) != null );

            foreach ( var type in types )
            {
                var plugin = Activator.CreateInstance( type ) as IPlugin;

                if ( plugin == null )
                {
                    Console.WriteLine( "Null" );
                    continue;
                }

                plugin.Loaded();
            }
        }
    }


Падает еще на первом try с сообщением: 


  Необработанное исключение типа "System.IO.FileLoadException" в mscorlib.dll
  Дополнительные сведения: Не удалось загрузить файл или сборку "C:\Users\anweledig\Documents\Visual
Studio 2015\Projects\Anweledig\ConsoleApplication\bin\Debug\Plugins\TestPlugin.dll"
либо одну из их зависимостей. Данное имя сборки или база кода недействительны. (Исключение
из HRESULT: 0x80131047)

    


Ответы

Ответ 1



Вы можете просто загрузить другую библиотеку. Все ее зависимости будут автоматически загружены. Проблема может быть только в случае, если библиотека лежит не в той же папке, в которой лежит ваше приложение, и вы при этом загружаете ее через Assembly.LoadFrom. Чтобы это обойти, вам нужно указать рантайму что зависимости надо искать в папке плагина, а не в папке вашего приложения. Тогда можно будет использовать обычный Assembly.Load и заодно заработает станадартный механизм загрузки сборок. Для этого можно использовать создание аппдомена с указанием AppDomainSetup.ApplicationBase Т.е. схема примерно такая: У вас есть базовая dll для плагинов - MyApp.SDK, в ней базовый класс (а лучше - интерфейс): public abstract class Plugin { public abstract void Loaded(); public abstract void Unload(); } в ней же код загрузки и вызова плагина (для простоты) public static class PluginInvoker { public static void InvokePlugin() { var pluginAssembly = Assembly.Load("SomePlugin"); var pluginType = pluginAssembly.GetTypes().Where(t => typeof(Plugin).IsAssignableFrom(t)).Single(); Plugin plugin = (Plugin)pluginType.GetConstructor(new Type[0]).Invoke(null); plugin.Loaded(); } } есть реализация этого плагина в SomePlugin.dll: public class Test: MyApp.SDK.Plugin { public override void Loaded() { Console.WriteLine("Loaded"); } public override void Unload() { Console.WriteLine("Unloaded"); } } в SomePlugin есть референс на MyApp.SDK. И есть главное приложение, в котором есть ссылка на MyApp.SDK, но нет ссылки на SomePlugin: static void Main(string[] args) { AppDomainSetup setup = new AppDomainSetup(); setup.ApplicationBase = @"C:\Projects\MyApp\SomePlugin\bin\Debug\"; AppDomain pluginDomain = AppDomain.CreateDomain("plugin", null, setup); pluginDomain.DoCallBack(PluginInvoker.InvokePlugin); } ApplicationBase задает папку, откуда AppDomain будет загружать сборки - т.к. это папка плагина, то все, на что он ссылается, будет корректно загружено. Если плагины подгружаются из подпапки приложения (например, из Plugins), то в вместо AppDomainSetup.ApplicationBase можно использовать AppDomainSetup.PrivateBinPath. Если же при этом плагины вообще не планируется выгружать, и все плагины лежат в одной папке (без подпапок на каждый из плагинов) - то можно обойтись без отдельного AppDomain, просто дописав путь к папке с плагинами в секцию app.config/. код примера на github: https://github.com/PashaPash/PluginLoadSample

четверг, 9 апреля 2020 г.

Как создать объект с помощью рефлексии?

#java #рефлексия

                    
Существует несколько вариантов для создания объекта в Java. Слышал, что есть вариант
с рефлексией. Как это можно реализовать?
А также в чем суть названия этого метода создания объекта?
    


Ответы

Ответ 1



Class.newInstance() Constructor.newInstance() Unsafe.allocateInstance() Десериализация объекта.

Ответ 2



Вся суть рефлексии в динамичности. В этом случае вы можете создавать тот объект, который нужен в зависимости от условий. Вы можете получить название класса из БД, в результате вычислений, из файла и т.д. С помощью рефлексии объект создавать можно следующим образом: Допустим, что у нас есть класс Reflect, объект которого мы будем создавать public class Reflect { public Reflect () { System.out.println("Hello from reflect class constructor"); } } Напишем класс Main, в котором будет создаваться объект класса Reflect public class Main { public static void main (String args[]) throws ClassNotFoundException, IllegalAccessException, InstantiationException { Class c = Class.forName("Reflect"); Object object = c.newInstance(); } } Output: Hello from reflect class constructor

Ответ 3



наверное вы имеете ввиду class.newInstance();

понедельник, 30 марта 2020 г.

Почему в php рефлексия показывает что интерфейс это абстрактный класс?

#php #интерфейс #рефлексия #php5


Можете, пожалуйста, подсказать почему в php 5.6.30 данный код:

interface IInterface {
  public function someMethod();
  public function anotherMethod();
}
function classData( ReflectionClass $class )
{
    $details = "";
    $name = $class->getName();

    if ( $class->isInterface() ) {
        $details .= "$name -- это интерфейс
"; } if ( $class->isAbstract() ) { $details .= "$name -- это абстрактный класс
"; } return $details; } $class_info = new ReflectionClass('IInterface'); echo classData($class_info); выводит следующий результат: IInterface -- это интерфейс IInterface -- это абстрактный класс Т.е. почему интерфейс определяется как абстрактный класс? Если удалить методы из интерфейса, то отобразится: IInterface -- это интерфейс Интересный факт: hhvm лишён этого недостатка


Ответы

Ответ 1



Существует 2 типа «абстрактности» в php: explicit - класс, явно определённый, как abstract. implicit - класс/интерфейс, содержащий абстрактные методы. Проверить на explicit абстрактность можно так: if ($class->getModifiers() & ReflectionClass::IS_EXPLICIT_ABSTRACT) { // Перед нами абстрактный класс } Демонстрация

суббота, 21 марта 2020 г.

Проверить генерик-тип интерфейса в C#?

#c_sharp #net #рефлексия #net_core


У меня есть тип AType который реализует генерик-интерфейс IA
Тип BType реализует интерфейс IC.
Как я могу проверить связан AType с IC или нет?

class AType : IA
{}

class BType : IC
{}

interface IA
{ }

interface IC
{ }


Тип BType может быть любым и мне о нем ничего неизвестно. У меня есть экземпляр AType
и мне нужно понять реализует ли он IC через generic тип промежуточного интерфейса IA
Проверка ниже не работает: 

var aInstance = new AType();
aInstance is IA // false
...


Также для Type.IsAssignableFrom(Type)

typeof(IC).IsAssignableFrom(aInstance.GetType()) // false

    


Ответы

Ответ 1



Проверка ниже не работает: Верно, потому что компилятор ничего не знает о вариантности интерфейса. Если ваш интерфейс IA фактически является ковариантным, то укажите это явно: interface IA { } потом: var aInstance = new AType(); Console.WriteLine(aInstance is IA); // True Но явная вариантность — это ограничение и интерфейс может считаться ковариантным только в случае когда все его члены используют тип T только для возврата. Скомпилируется: interface IA { T Method(); } Не скомпилируется: interface IA { void Method(T t); } подробно: Вариативность в универсальных интерфейсах (C#) Если ваш тип не является ковариантным, то вам придется разбирать это явно. Для проверок внутри класса можно написать что-то вроде: class AType : IA { public bool HasParamenterOfTypeIC() { return typeof(IC).IsAssignableFrom(typeof(T)); } } тогда: var a = new AType(); Console.WriteLine(a.HasParamenterOfTypeIC()); // True var b = new AType(); Console.WriteLine(b.HasParamenterOfTypeIC()); // False для проверок снаружи вы должны еще и явно достать дженерик-параметр и проверить его на совместимость: class OType : IA { } class AType : IA { } class Program { static void Main() { Console.WriteLine(HasParamenterOfTypeIC(typeof(AType))); // True Console.WriteLine(HasParamenterOfTypeIC(typeof(OType))); // False } static bool HasParamenterOfTypeIC(Type type) { return type .GetInterfaces() .SelectMany(i => i.GetGenericArguments()) .Any(i => typeof(IC).IsAssignableFrom(i)); } }

воскресенье, 15 марта 2020 г.

Создание ПО с плагинами

#c_sharp #delphi #plugin #desktop #рефлексия


По долгу службы требуется реализация довольно сложного десктопного ПО. Как одно из
требований — плагины (подключаемые модули), которые могут быть очень разнообразными:
от определения новых типов данных до работы с интерфейсом (добавление форм, кнопок
и т.п.). Разумеется, также требуются аналитика, обработка данных, сохранение в разные
БД и т.д.

Платформы для выбора — C# или Delphi (т.к. есть прототип, реализующий 90% потребного
функционала, но в режиме «спагетти»).

Если с Delphi всё понятно — средство загрузки/выгрузки плагинов делать руками, то
вот с C# не всё так прозрачно.

Пока что быстрый поиск показал следующие варианты:


MEF: довольно просто в реализации, но нельзя изолировать плагины в отдельных AppDomain
(что довольно-таки важно, это существенное архитектурное преимущество .NET вообще и
шарпа в частности);
MAF: переусложнено, замудрённо, и, с виду, уже не поддерживается. С другой стороны —
мощная изоляция;
самостоятельная реализация на reflection (например, так), с возможностью загрузки
в AppDomain и прочим. Но придётся много велосипедить, чего в общем-то не хочется.


Есть ещё варианты? Может, что-то не было учтено?

UPD: добавил ссылки.
    


Ответы

Ответ 1



Для C# есть встроенное готовое решение от Microsoft: System.Addin. Позволяет конфигурировать плагины так, чтобы использовать их в том же AppDomain'е, или в выделенном другом, или каждый в своём, или вообще в отдельном процессе. Не понимаю, почему везде советуют MEF. Это решение именно для расширяемости: код, который вы загружаете, считается доверенным и очень мало отличается от основного кода приложения, поэтому возможности выгрузки и управление правами напрочь отсутствуют. Самостоятельный велосипед на reflection написать можно, но придётся довольно серьёзно разбираться в тонкостях наподобие Fusion и Load context, так что я бы не советовал тратить время. Обновление: Ага, System.Addin — это то, что вы называете MAF.

Ответ 2



Зависит от специфических требований к вашей системе. Так ли нужна изоляция в отдельный домен? Если код ваших плагинов не предполагает взаимодействия с Native библиотеками, то и исключения, выбрасываемые из плагина, не поломают вашу программу целиком. Вы вполне можете их перехватить, по стеку установить плагин-виновник и предложить пользователю в следующий раз не загружать его. Ну да, не так круто, как в динамике выгрузить домен, но зато насколько меньше возни. Вот Студия же работает именно так. Ну а если ваши плагины способны нарушить работу процесса на уровне ОС, то ляжет весь процесс приложения вместе с CLR и доменами. Поэтому с MAF я бы не связывался. Что до остального, могу посоветовать Mono.Addins. По возможностям превосходит MEF. Документация есть, но не исчерпывающая. Примеров маловато. Также есть система ICSharpCode.Core, используемая в SharpDevelop, она тоже мощная, есть исходники (сам шарпдевелоп). Но документации почти нет, и она сильно устарела.

среда, 4 марта 2020 г.

Java. Хранится ли рефлексивная информация о классе в памяти JVM?

#java #jvm #рефлексия


Вопрос в следующем, хранит ли JVM информацию о классе (например Field[], Method[],
etc.) в памяти, после загрузки класса класслоадером и можно ли держать ссылки на эту
информацию?
    


Ответы

Ответ 1



Это зависит от того, какую JVM вы используете. Например, у Hotspot JVM в свежих версиях (8+) эта информация хранится в MetaSpace, который является частью native heap. Держать ссылки на эту информацию можно, если она вам нужна. Если она не нужна, по идее лучше не держать, чтобы можно было выгрузить класс.

Ответ 2



Если я правильно понимаю вопрос, то да, jvm хранит мета-информацию о полях и методах классов в хипе. Для Java до 7 версии в PermGen, для Java 8+ в MetaSpace.

вторник, 25 февраля 2020 г.

Запись вызова метода в лог

#c_sharp #attribute #net #рефлексия


Есть такой код:
public class Foo
{
    [Log("Calling bar")]
    public void Bar()
    {
    }
}

Как сделать, чтобы при вызове метода Bar что-то писалось в лог?
Хотелось бы какое-нибудь событие типа OnCall.    


Ответы

Ответ 1



Аспектно-ориентированное программирование Ведение лога и обработка ошибок — типичные примеры сквозной функциональности. PostSharp - одна из лучших библиотек АОП для c# Вот пример аспекта: public class LogAttribute : PostSharp.Aspects.OnMethodBoundaryAspect { // Выполняется перед входом в метод. public override void OnEntry(MethodExecutionArgs args) { Console.WriteLine("Входим в метод {0} класса {1}", args.Method.Name, args.Method.DeclaringType.FullName); } // Выполняется при успешном завершении работы метода public override void OnExit(MethodExecutionArgs args) { Console.WriteLine("Метод {0} класса {1} успешно отработал", args.Method.Name, args.Method.DeclaringType.FullName); } } Быстрый старт PostSharp. Решение задач логгирования и аудита Несколько полезных аспектов для PostSharp

понедельник, 24 февраля 2020 г.

Как правильно использовать методы сборки в другом домене?

#c_sharp #net #рефлексия


Если создать домен и загрузить в него сборку, а потом используя метод GetAssemblies,
достать сборки, то выгружая домен, сборка остается в основном домене приложения и с
ней ничего сделать нельзя, удалить например.

Каким образом можно использовать методы сборки из чужого домена, при этом выгружая
домен выгрузить и сборку из приложения?

Вот код которым я это делаю:

using System;
using System.IO;  
using System.Reflection;


namespace Test
{
internal static class Program
{
    private static void Main()
    {
        var appDomain = AppDomain.CreateDomain( "test" );
        AssemblyLoader.Run(appDomain);

        Console.WriteLine("Сборка загружена");

        foreach ( var assembly in appDomain.GetAssemblies () )
        {
            Console.WriteLine ( assembly.GetName () );
        }

        Console.ReadLine();

        AppDomain.Unload( appDomain );

        Console.WriteLine("Домен выгружен");
        //Не удается удалить сборку из каталога, она не выгрузилась!
        Console.ReadLine();
    }
}

public static class AssemblyLoader
{
    public static void Run( AppDomain appDomain )
    {
        appDomain.DoCallBack( Invoke );
    }

    private static void Invoke()
    {
        Assembly.LoadFile( Path.Combine( Environment.CurrentDirectory, "test.dll" ) );
    }

}


}
    


Ответы

Ответ 1



Если вы передаёте объект из другого домена, вы этим самым загружаете его в ваш домен, чего вы как раз хотите избежать. Решением может быть передавать примитивные типы. Чтобы не ограничивать себя простыми колбеками, вам нужно воспользоваться MarshalByRefObject (они не копируются между доменами, а выполняются в том домене, где созданы). Итак, вот рабочий код. Это плагин, DomainsPlugin.dll: namespace DomainsPlugin { public class Plugin { public IEnumerable GetNames() { return AppDomain.CurrentDomain.GetAssemblies().Select(asm => asm.GetName()); } } } Ничего особого, просто рабочий метод. Теперь главная программа: namespace DomainsMain { class Program { static void Main(string[] args) { // в этом каталоге бежит программа var executableDir = Path.GetDirectoryName( Assembly.GetExecutingAssembly().Location); // это каталог, где лежит плагин. // у вас он будет лежать, понятно, в другом месте var pluginDir = Path.GetFullPath(Path.Combine( executableDir, "..", "..", "..", "DomainsPlugin", "bin", "Debug")); // оригинал плагина var pluginSourceFile = Path.Combine(pluginDir, "DomainsPlugin.dll"); // а сюда мы его скопируем, и отсюда будем загружать var pluginWorkingFile = Path.Combine(executableDir, "DomainsPlugin.dll"); // копируем File.Copy(pluginSourceFile, pluginWorkingFile, overwrite: true); // окей, теперь новый домен var pluginDomain = AppDomain.CreateDomain("Plugin"); // теперь, создаём экземпляр нашего класса в новом домене // у нас на него реально лишь прокси-объект var resident = (Resident)pluginDomain.CreateInstanceAndUnwrap( Assembly.GetExecutingAssembly().FullName, "DomainsMain.Resident"); // получили данные resident.Obtain(); // выводим их foreach (var r in resident.Result) Console.WriteLine(r.ToString()); // выгружаем домен... AppDomain.Unload(pluginDomain); // ... и удаляем плагин File.Delete(pluginWorkingFile); } } // простой класс, будет выполняться в другом домене public class Resident : MarshalByRefObject { public List Result; public void Obtain() { // загружаем библиотеку var asm = Assembly.LoadFrom("DomainsPlugin.dll"); var type = asm.GetType("DomainsPlugin.Plugin"); // и вызываем функцию из неё через рефлексию // можно было бы закастить к интерфейсу, если объявить его в // этой или другой общей dll-ке var p = Activator.CreateInstance(type); var method = type.GetMethod( "GetNames", BindingFlags.Instance | BindingFlags.Public); var result = (IEnumerable)method.Invoke(p, null); // сохраняем результат. это поле будет доступно из первоначального домена Result = result.ToList(); } } } На моей машине из-под Visual Studio выдаёт: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Microsoft.VisualStudio.HostingProcess.Utilities, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a DomainsMain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 DomainsPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null Обновление: резидентная функция (Obtain()) вполне может возвращать значение. Но это значение должно быть сериализируемым, чтобы «протиснуться» между доменами. Для нашего примера, подправляем класс Resident: public class Resident : MarshalByRefObject { public List Obtain() // <-- поменяли возвращаемый тип { // и убрали свойство Result // загружаем библиотеку var asm = Assembly.LoadFrom("DomainsPlugin.dll"); var type = asm.GetType("DomainsPlugin.Plugin"); // и вызываем функцию из неё через рефлексию // можно было бы закастить к интерфейсу, если объявить его в // этой или другой общей dll-ке var p = Activator.CreateInstance(type); var method = type.GetMethod( "GetNames", BindingFlags.Instance | BindingFlags.Public); var result = (IEnumerable)method.Invoke(p, null); return result.ToList(); } } Теперь вызов из основного кода выглядит так: // получили данные var result = resident.Obtain(); // выводим их foreach (var r in result) Console.WriteLine(r.ToString());

Что такое .class?

#java #рефлексия


Constructor  constructor = User.class.getConstructor(new Class[]{String.class,String.class,String.class});
System.out.println("Constructor  "+constructor);
constructor.newInstance("Hello","From","Reflection");


Из данного примера мне понятно что при передачи конструктору создаётся Обьект массива
типа Class. 

Но вводит в заблуждение: Class.class после чего позволяется вызывать методы Reflection
API. Что означает этот .class ? 

Я знаю что для доступа к методам надо создать обьект любого класса или если метод
статичный то доступ будет произведен через имя класса.. В случае с доступом к Reflection
API не понятно это окончание .class, я могу вызвать .class у любого класса или интерфейса
или примитива int.class как JVM (если так правильно будет сказать) относится к такого
рода конструкциям ? Что это и почему оно используется ? 
    


Ответы

Ответ 1



Обращение к .class после имени типа возвращает объект типа Class. Этот объект содержит информацию о типе (будь то класс или интерфейс) и используется в тех местах, где нужно передать информацию о типе (рефлексия как один из примеров). Вызов .class на типе эквивалентен вызову getClass() на экземпляре типа. Обычно .class используется там, где нужно указать тип, но нет конкретного экземпляра этого типа. Пример для String: System.out.println(String.class.getName()); System.out.println("hello".getClass().getName()); В вашем примере в первой строке вы находите конструктор класса User, который принимает три строковых параметра. Для указания типов параметров используется String.class.

пятница, 14 февраля 2020 г.

как получить все классы в пакете javaapplication7?

#java #рефлексия #package


Есть пакет javaapplication7, в нем 3 простых класса A,B,C, затрудняюсь получить их.
    


Ответы

Ответ 1



Вот пример класса, который сканирует пакет, и возвращает список его классов вpublic class ClassFinder { private static final char PKG_SEPARATOR = '.'; private static final char DIR_SEPARATOR = '/'; private static final String CLASS_FILE_SUFFIX = ".class"; private static final String BAD_PACKAGE_ERROR = "Unable to get resources from path '%s'. Are you sure the package '%s' exists?"; /** * Возвращает список классов в пакете */ public static List> find(String scannedPackage) { String scannedPath = scannedPackage.replace(PKG_SEPARATOR, DIR_SEPARATOR); URL scannedUrl = Thread.currentThread().getContextClassLoader().getResource(scannedPath); if (scannedUrl == null) { throw new IllegalArgumentException(String.format(BAD_PACKAGE_ERROR, scannedPath, scannedPackage)); } File scannedDir = new File(scannedUrl.getFile()); List> classes = new ArrayList<>(); for (File file : scannedDir.listFiles()) { classes.addAll(find(file, scannedPackage)); } return classes; } private static List> find(File file, String scannedPackage) { List> classes = new ArrayList<>(); String resource = scannedPackage + PKG_SEPARATOR + file.getName(); if (file.isDirectory()) { for (File child : file.listFiles()) { classes.addAll(find(child, resource)); } } else if (resource.endsWith(CLASS_FILE_SUFFIX)) { int endIndex = resource.length() - CLASS_FILE_SUFFIX.length(); String className = resource.substring(0, endIndex); try { classes.add(Class.forName(className)); } catch (ClassNotFoundException ignore) { } } return classes; } } Пример вызова List> classes = ClassFinder.find("examples.concurrency");

Ответ 2



Можете воспользоваться библиотекой: Class graph Maven Central Пример: try (ScanResult scanResult = new ClassGraph() .whitelistPackages("javax.persistence") // Сканирует пакет javax.persistence и все его подпакеты .scan()) { for (ClassInfo classInfo : scanResult.getAllClasses()) { System.out.println(classInfo.getName()); } }

Ответ 3



Могу предложить библиотеку Reflections. С ее помощью можно легко получить информацию о классах для заданного пакета: private static List> getAllClassesFrom(String packageName) { return new Reflections(packageName, new SubTypesScanner(false)) .getAllTypes() .stream() .map(name -> { try { return Class.forName(name); } catch (ClassNotFoundException e) { return null; } }) .filter(Objects::nonNull) .collect(Collectors.toList()); } Зависимость: org.reflections reflections 0.9.10

четверг, 13 февраля 2020 г.

C#: построение дерево объектов выгруженных в память объектов

#c_sharp #рефлексия


Добрый день.

Сегодня загорелся таким вопросом: если приложение (например win-сервис) используется
в своей работе какие-то экземпляры классов, то значит они где-то хранятся, а значит
можно получить их перечень.

Можно ли как-то с помощью C# узнать, какие объекты выгружены в память, в каком кол-ве,
владельцем которых есть конкретный виндовс-сервис?
Это я планирую сделать нечто вроде профайлера.

Спасибо.
    


Ответы

Ответ 1



Попробуйте компонент CLR Memory Diagnostics (ClrMD): int pid = Process.GetProcessesByName("HelloWorld")[0].Id; using (DataTarget dataTarget = DataTarget.AttachToProcess(pid, 5000)) { string dacLocation = dataTarget.ClrVersions[0].TryGetDacLocation(); ClrRuntime runtime = dataTarget.CreateRuntime(dacLocation); ClrHeap heap = runtime.GetHeap(); foreach (ulong obj in heap.EnumerateObjects()) { ClrType type = heap.GetObjectType(obj); ulong size = type.GetSize(obj); Console.WriteLine("{0,12:X} {1,8:n0} {2}", obj, size, type.Name); } } Вывод: 23B1D30 36 System.Security.PermissionSet 23B1D54 20 Microsoft.Win32.SafeHandles.SafePEFileHandle 23B1D68 32 System.Security.Policy.PEFileEvidenceFactory 23B1D88 40 System.Security.Policy.Evidence Более подробно можно почитать в статье .NET Crash Dump and Live Process Inspection. Конкретные сценарии работы с ClrMD можно найти в официальном репозитории. Плюс стоит обратить внимание на ClrMD.Extensions, которая несколько облегчает работу с ClrMD. С помощью этого компонента можно также анализировать файлы дампа. В случае, если вы умеете работать с unmanaged кодом, более правильно будет воспользоваться Profiling API.

пятница, 24 января 2020 г.

Использование в макросах строковых литералов в качестве типов

#cpp #шаблоны_с++ #макросы #рефлексия


В классе есть метаинформация, представленная в виде вектора пар значений строка-строка,
которые представляют собой строковое представление типа и имени члена класса.

Напрмиер:

class TObject
{
private:
    int  t_fMember;
    char t_sMember;
};


Для данного класса метаинформация представляется следующим множеством пар:

{
    {"int", "t_fMember"},
    {"char","t_sMember"}
}


Есть макрос, которые скрывает за собой шаблонную ф-ию:

#define GET_MEMBER_VALUE( MEM_TYPE, ... ) \
template  \
MEM_TYPE RetVal(...)\
{\
\
}


В сигнатуре и возвращаемом типе шаблонной ф-ии я писал не MEM_TYPE, а ##MEM_TYPE,
надеясь, что, например "int" превратится в int, однако, этого не произошло (чего и
следовало ожидать).

Есть ли способ проводить подобную конверсию ? Передавать тип как строковый литерал,
а затем делать обратное преобразование ? ("type" -> type)

UPD0: как бы я хотел это использовать:

#define GET_MEMBER_VALUE( MEM_TYPE, MEM_NAME, PTR_TO_OBJECT ) \
    template  \
    MEM_TYPE RetVal(...)\
    {\
        return PTR_TO_OBJECT->##MEM_NAME; \
    }


Отдаем указатель на объект, тип члена и его имя, обращаемся оператором -> к члену
по имени и возвращаем его значение.
    


Ответы

Ответ 1



Очевидно, из строки с именем нельзя получить указатель на член класса, просто потому что в предложенной схеме хранения метаинформации отсутствую указатели на члены классов. Более развитые системы хранения метаинформации (например, BOOST.FUSION) это умеют. #include #include #include #include #include #include #include struct TObject { int t_fMember; char t_sMember; } ; BOOST_FUSION_ADAPT_STRUCT( TObject, (int , t_fMember) (char, t_sMember) ); template struct memberByNameVisitor { ObjectType* ptr; const char* seek_name; ReturnType** result; template void visit_field( const char* field_name, T& field_value ) const {} void visit_field( const char* field_name, ReturnType& field_value ) const { if( strcmp( seek_name, field_name) ==0 ) *result = & field_value; } template void operator() (Index idx) const { visit_field( boost::fusion::extension::struct_member_name::call(), boost::fusion::at(*ptr) ); } }; template ReturnType& memberByName( ObjectType& ref, const char* name ) { typedef boost::mpl::range_c::value > Indices; ReturnType* result=nullptr; memberByNameVisitor visitor={&ref, name, &result}; boost::fusion::for_each( Indices(), visitor ); if(result!=nullptr) return *result; else throw std::invalid_argument("Filed is not found"); } int main(int argc, char *argv[]) { TObject test ={ 1234, 'A' }; std::cout << memberByName( test, "t_fMember" ) << std::endl; memberByName(test, "t_sMember") = 'C'; std::cout << memberByName(test, "t_sMember") << std::endl; return 0; }

пятница, 10 января 2020 г.

Свой атрибут/описание для public поля класса

#c_sharp #рефлексия #attribute


Есть у меня классы, у них открытые переменные. Я через reflection добираюсь до их
значений для последующего отображения/изменения.

По умолчанию - есть некоторый диапазон для изменения, условно -+20%.

Но для некоторых переменных есть свои особенности: -10%/+20% или 0..100. Это исключения,
они не многочисленны, но они есть.

Мне хочется, когда буду перебирать переменные, чтобы можно было прямо в коде задать
для переменной свой атрибут или не знаю как это называется - описание, которое я мог
бы пропарсить:

public int Length;

// Min: 0. Max: 100
public int Size;

[Range:20%]
public int Weight;


Чтобы было более наглядно: у Unity3D есть HideInInspector. Что-то похожее хочу сделать,
но более информативно.
    


Ответы

Ответ 1



Используйте для этого кастомные классы атрибутов, они для того и созданы, чтобы предоставлять мета-информацию об объектах в отражениях. Например, вот атрибут, позволяющий задавать диапазон для полей: [AttributeUsage(AttributeTargets.Field)] class RangeAttribute : Attribute { public int Percent { get; set; } public RangeAttribute (int percent) { Percent = percent; } } Задавать значение диапазона на поле можно так: class Foo { [Range(20)] public int Bar; } Ну а дальше — отражения: FieldInfo barField = typeof(Foo).GetField("Bar"); RangeAttribute barRange = barField.GetCustomAttribute(); int range = barRange != null ? barRange.Percent : 20; var foo = new Foo(); barField.SetValue(foo, 10); См.: Attributes Tutorial (MSDN) Writing Custom Attributes (MSDN) Creating Custom Attributes (MSDN)

четверг, 9 января 2020 г.

RTTI. Как обратить к статическому полю класса, имея объект Class для него?

#java #рефлексия #rtti


Имеем класс Allocator, который имеет метод allocate(Class). Как без знания того,
объект Class какого класса пришёл, вытащить из него поле с возможностью его изменить?

Вариант с использованием objOFclassClass.newInstance() не подойдёт. Охота без лишних
затрат памяти на создание объекта обойтись.  

class X {
    public static boolean f = false;
}

class Y {
    public static boolean f = false;
}

class Z {
    public static boolean f = false;
}

class Allocator {
    public static void allocate (Class c) throws Exception{
        // Предполагая, что (c.name == "X" или "Y" или "Z"), как сделать что то в духе:
        // c.setStaticField("f",true);  ???
    }
}

    


Ответы

Ответ 1



С помощью метода getDeclaredField получаем объект класса Field Изменяем поле с помощью вызова метода set у этого объекта Field field = c.getDeclaredField("имя_поля"); field.set(null, true /* новое значение */); Код на Ideone

понедельник, 6 января 2020 г.

C# рефлексия. Получение значения приватного поля экземпляра класса?

#c_sharp #рефлексия


Есть экземпляр класса Class1, каким образом можно получить его aValue поле?
Вопрос крайне глупый, понимаю... и все же. Получается получить только статические
поля, а для экземпляров как быть?

public class Class1{

    private int aValue;
    public Class1(int a){
        this.aValue = a;
    }
}

Class1 cls = new Class1(10);

    


Ответы

Ответ 1



Нужно указать маску: Class1 cls = new Class1(10); FieldInfo fieldInfo = typeof(Class1).GetField("aValue", BindingFlags.Instance | BindingFlags.NonPublic); int a = (int)fieldInfo.GetValue(cls);

Ответ 2



Один из принципов ООП - Инкапсуляция, означает что доступ к "некоторым" свойствам класса возможен только "внутри капсулы" из метода класса; Напиши метод public int GetValue() {return aValue}

суббота, 4 января 2020 г.

Как проверить, что класс В наследуется от А? (java)

#java #рефлексия


Когда у нас есть объект типа В и класс А - всё просто:

B b;
if (b instanceof A) ...


А если у нас нет экземпляра В, а есть только сам класс?

Раньше точно делал, но сейчас найти не могу.
Бегу по рефлексии, и мне нужно определить, является ли field.getType() наследником
некоторого класса.
    


Ответы

Ответ 1



Судя по этому ответу Нужна функция isAssignableFrom Super.class.isAssignableFrom(Sub.class)

среда, 1 января 2020 г.

Рефлексия. Как вызвать метод с ref generic параметрами?

#c_sharp #generics #рефлексия #ref


Имеем такой класс и метод

public class TestClass
{
    public void Swap(ref T first, ref T second)
    {
        T tmp = second;
        second = first;
        first = tmp;
    }
}


Пытаюсь задействовать рефлексию и вызвать метод

[TestMethod]
public void InvokeGenericMethod()
{
    MethodInfo method = typeof(TestClass).GetMethod("Swap");
    MethodInfo methodWithInt = method.MakeGenericMethod(typeof(int));

    int one = 1;
    int two = 2;
    object[] arguments = { one, two };
    methodWithInt.Invoke(this, arguments);//здесь ошибка

    Assert.AreEqual(one, 2);
}


и получаю ошибку {"Объект не соответствует конечному типу."}

Как это делается? Гуглеж приводил к примерам с одним параметром out и чего-то все
вызывалось как обычно, т.е. массив аргументов создавался как у меня, а далее обычный
вызов через Invoke(). Какие идеи?
    


Ответы

Ответ 1



Вы вызываете нестатический метод, и должны передать в качестве первого аргумента Invoke объект, у которого вы этот метод хотите вызвать. И это должен быть объект того класса, метод которого вы вызываете: methodWithInt.Invoke(new TestClass(), arguments); Или вы можете поменять метод на статический, и передавать null в качестве первого аргумента: public class TestClass { public static void Swap(ref T first, ref T second) { T tmp = second; second = first; first = tmp; } } methodWithInt.Invoke(null, arguments); Кстати, в MSDN по Invoke подробно расписано, в каких случаях он бросает TargetException. Стандартная документация значительно облегчает поиск причины ошибки :)

Рефлексия в c#. Как получить исходный код метода?

#c_sharp #рефлексия #делегаты


Как получить исходный код метода? У меня есть функция которая принимает делегат Predicate
и мне нужно вывести исходный код функции, которую туда передали.
Сама функция

public string GetSource(Predicate match) {
  Console.WriteLine("Source method");
}


Применение этой функции

GetSource(x => x.Name == "name");


Результат вызова функции в консоли: x.Name == "name"
    


Ответы

Ответ 1



Похожие вещи делаются в C# через так называемые деревья выражений. Эта тема сложная, которая требует ознакомления, и её невозможно осветить в одном ответе на Stack Overflow. Если вкратце, то для начала вы должны объявить параметр не как Func, Action или Predicate, а как Expression> или Expression>. public string GetSource(Expression> expression) { . . . } В этом случае вы не сможете просто вызывать метод, предварительно его придётся скомпилировать. На зато вы можете разобрать его на составные части. В случае x.Name == "name" в корне дерева будет находиться объект типа BinaryExpression со свойством NodeType равным ExpressionType.Equal. Левый и правый дочерние узлы этого узла будут представлять x.Name и "name" соответственно. Проще всего пройтись в отладчике по этому дереву и посмотреть, какие объекты там встречаются. Чтобы вывести всё это на экран, можно просто вызвать метод expression.ToString(). Но в сложных случаях придётся формировать строку из дерева выражения самостоятельно.

Ответ 2



С помощью рефлексии нельзя получить исходный код метода, так как рефлексия возвращает только ту информацию, которая есть в скомпилированной сборке. Рефлексия может дать IL-байткод метода, но не исходный код, ей неоткуда взять его. Исходный код нужно получать из каких-то других источников: 1) Отладочные символы Если получение исходного кода необходимо только на машине, где ведется разработка, можно воспользоваться отладочными символами. В PDB-файлах, генерируемых компилятором, хранится информация о соответствии строк файлов исходного кода инструкциям в IL-байткоде (именно благодаря этому отладчик может при возникновении исключения может указать на конкретную строку). Определив положение начала и конца метода, считать его код из исходников - дело техники. В символах присутствует каждый метод, который физически есть в сборке, в том числе и анонимные, поэтому решение вполне применимо и для условий из лямбда-выражений. Так как символы ссылаются на исходники по абсолютным путям, чтобы он сработал на других машинах, проект понадобится перенести на них в точности по такому же пути, как он был расположен на машине разработчика. Естественно, необязательно распространять проект целиком - главное, чтобы файл с нужным методом был доступен. Формат PDB не документирован, однако существует несколько библиотек с открытым исходным кодом от Microsoft для работы с ним, например Microsoft.Diagnostics.Runtime. 2) Декомпиляция Если исходники недоступны или нет символов, можно воспользоваться одним из декомпиляторов, чтобы восстановить их из байткода на лету. Например, библиотека ICSharpCode.Decompiler, движок декомпилятора ILSpy, поддерживает декомпиляцию типа в синтаксическое дерево, которое можно обойти и найти нужный метод. В том числе, с помощью нее программа можно спокойно декомпилировать саму себя! Правда, чтобы корректно обрабатывать лямбды, придется отключить подстановку кода анонимных методов - в противном случае мы их в синтаксическом дереве не найдем. Пример получения исходного кода метода двумя данными способами: using System; using System.Text; using System.Collections.Generic; using System.IO; using System.Linq; using System.Diagnostics; using System.Reflection; using Microsoft.Diagnostics.Runtime; using Microsoft.Diagnostics.Runtime.Utilities.Pdb; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.CSharp; using ICSharpCode.Decompiler.CSharp.Syntax; namespace ConsoleTest1 { class Program { public static string GetSourceFromPdb(Predicate match) { int token = match.Method.MetadataToken; //построим путь к файлу символов string module_path = match.Method.Module.FullyQualifiedName; string pdb_path = Path.Combine( Path.GetDirectoryName(module_path), Path.GetFileNameWithoutExtension(module_path) + ".pdb" ); StringBuilder sb = new StringBuilder(); PdbReader reader = new PdbReader(pdb_path); using (reader) { //найдем метод в символах var func = reader.GetFunctionFromToken((uint)token); foreach (PdbSequencePointCollection coll in func.SequencePoints) { //считываем файл исходников string[] lines = File.ReadAllLines(coll.File.Name, System.Text.Encoding.UTF8); //найдем номера строк в файле, соответствующие началу и концу метода var points_sorted = coll.Lines. Where((x)=> x.LineBegin <= lines.Length && x.LineEnd<=lines.Length). OrderBy((x) => x.Offset); PdbSequencePoint start = points_sorted.First(); PdbSequencePoint end = points_sorted.Last(); bool reading = false; int index_start; int index_end; //считаем код метода из исходников for(int i=1; i<=lines.Length;i++) { string line = lines[i-1]; index_start = 0; index_end = line.Length; if (!reading) { if (i >= start.LineBegin) { //первая строка reading = true; index_start = start.ColBegin - 1; if (index_start < 0) index_start = 0; } } if (reading) { if (i >= end.LineEnd) { //последняя строка index_end = end.ColEnd - 1; if (index_end > line.Length) index_end = line.Length; sb.AppendLine(line.Substring(index_start, index_end - index_start)); break; } //считывание текущей строки sb.AppendLine(line.Substring(index_start, index_end - index_start)); } } } } return sb.ToString(); } public static AstNode FindNode(AstNode root,string match) { //поиск метода в синтаксическом дереве var children = root.Children; foreach (AstNode x in children) { var s = x.ToString(); if (s == match && x.Parent.NodeType == NodeType.Member) { return x.Parent; } AstNode res = FindNode(x, match); if (res != null) return res; } return null; } public static string GetSourceDecompiled(Predicate match) { string module_path = match.Method.Module.FullyQualifiedName; var settings = new DecompilerSettings(); settings.AnonymousMethods = false; //отключим подстановку кода анонимных методов var decompiler = new CSharpDecompiler( module_path, settings ); //декомпилируем тип, содержащий метод SyntaxTree tree = decompiler.DecompileType( new ICSharpCode.Decompiler.TypeSystem.FullTypeName(match.Method.DeclaringType.FullName) ); //найдем метод в синтаксическом дереве var children = tree.Children.ToList(); AstNode res = null; foreach (var x in children) { res = FindNode(x, match.Method.Name); if (res != null) break; } string s = ""; if (res != null) s = res.ToString(); return s; } static void Main(string[] args) { string source; Console.WriteLine("*** Source from PDB: ***"); source = GetSourceFromPdb( (s) => s == "Test" || s.Length==0); Console.WriteLine(source); Console.WriteLine("*** Decompiled source: ***"); source = GetSourceDecompiled((s) => s == "Test" || s.Length==0); Console.WriteLine(source); Console.ReadKey(); } } } Результат: *** Source from PDB: *** s == "Test" || s.Length==0 *** Decompiled source: *** [CompilerGenerated] private static bool
b__6 (string s) { return s == "Test" || s.Length == 0; }

понедельник, 30 декабря 2019 г.

Как привести к generic типу?

#c_sharp #рефлексия


private bool TryParseOf(string s, out TType result)
{
    if (typeof(TType) == typeof(int))
    {
        var parseSuccessful = int.TryParse(s, out var innerResult);
        result = innerResult; // в этой строке проблема
        return parseSuccessful;
    }
    throw new NotImplementedException();
}


нельзя просто взять и привести. TType может быть int, string, etc.
    


Ответы

Ответ 1



private bool TryParseOf(string s, out TType result) { var converter = TypeDescriptor.GetConverter(typeof(TType)); try { result = (TType)converter.ConvertFromString(s); } catch (ArgumentException) { result = default; return false; } return true; }

Ответ 2



Если делаем для простых типов, то public class MyClass { public bool TryParseOf(string s, out TType result) { var converter = TypeDescriptor.GetConverter(typeof(TType)); if (converter.CanConvertFrom(typeof(string))) { result = (TType)converter.ConvertFrom(s); return true; } result = default(TType); return false; } } Проверка var c = new MyClass(); if (c.TryParseOf("11", out int i)) Console.WriteLine(i); // 11 if (c.TryParseOf("11", out double j)) Console.WriteLine(j); // 11

Ответ 3



В принципе, приведение можно сделать через object, но я не уверен, будут ли там тогда лишняя упаковка и распаковка. Если будут, то способ мне не очень нравится. https://ideone.com/ziADyJ using System; public class Test { private static bool TryParseOf(string s, out TType result) { if (typeof(TType) == typeof(int)) { var parseSuccessful = int.TryParse(s, out int innerResult); result = (TType)(object)innerResult; return parseSuccessful; } throw new NotImplementedException(); } public static void Main() { Console.WriteLine("{0}: {1}", TryParseOf1("123", out var x), x); } }

пятница, 27 декабря 2019 г.

JavaCompiler API ошибка java.lang.NoClassDefFoundError при вызове метода ч/з Reflection API

#java #рефлексия


Задача заключается в использовании классов/объектов в динамическом классе(созданного
из строкового представления). см. javaFileContents

Проблема заключается в объявлении и дальнейшей инициализации объектов. После прохода
строки System.out.println(Connector.class); возникает ошибка: java.lang.NoClassDefFoundError:
controller/Connector, аналогично и со строками в комментариях. Понятно, что ошибка
связана с тем, что компилятор "не знает" о классе Connector, но пакет, в котором он
расположен, подключен ч/з JavaCompiler API(параметр optionList метода getTask) и явно
импортирован import controller.*;. Путь к jar'нику валидный(переменная pathToPackage).
В случае, если путь указан не верно, после прохода строки import controller.*; и import
model.*; компилятором, генерируется ошибка: 

/CompiledClass.java:4: error: package controller does not exist
import controller.*;
^
/CompiledClass.java:5: error: package model does not exist
import model.*;
^


Оба пакета располагаются по адресу: C:\Users\leonid\AppData\Roaming\JDeveloper\system12.1.3.0.41.140521.1008\o.j2ee\drs\forum\ControllerEJB.jar,
те ./controller и ./model и в этих директориях соответственно откомпилированные классы.

Т.е. в итоге компилятор видит пакет и удачно импортирует его в класс, но не видит
классов внутри пакета, использование других классов/объектов, из стандартных java-lib,
безошибочно компилируются, допустим после строки System.out.println(String.class) ошибки
не возникает и результат удачно выводится.

Код:

public class CompilerJavaManager {

    public static void compileJavaFileObject(StringBuilder inputString, Writer jspOut,
String sessionId, String pathToPackage) throws Exception {
        String className = "CompiledClass";
        String classMethod = "methodOf" + className;
        Class[] parameters = new Class[] { sessionId.getClass() };
        Object[] arguments = new Object[] { sessionId };
        Class compiledClass = null;
        //Class c = Class.forName(className);

        StringBuilder javaFileContents =
            new StringBuilder("" +
                //"package compiled;" +
                '\n' +
                "import java.io.*;\n" +
                "import java.util.*;\n" +
                "import controller.*;\n" +
                "import model.*;\n" +
                '\n' +
                "public class " + className +"{\n" +
                "   private Writer out = null;\n" +
                //"   private Connector connector = null;\n" +
                //"   private UPContainer container = null;\n" +
                //"   private Controller controller = null;\n" +
                //"   private userHandler handler = null;\n" +
                '\n' +
                "   public " + className +"(Writer out){\n" +
                "       this.out = out;\n" +
                "   }\n" +
                '\n' +
                "   public void " + classMethod + "(String sessionId) throws java.io.IOException{\n" +
                "       System.out.println(Connector.class);" +
                //"       Connector connector = Connector.getConnector();\n" +
                //"       UPContainer container = Connector.getConnector().getContainerInstance(sessionId);\n" +
                //"       Controller controller = container.getControllerInstance();\n" +
                //"       userHandler handler = container.getUserHandlerInstance();\n" +
                        //inputString +
                "   }\n" +
                "}\n");

        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector diagnosticsCollector = new DiagnosticCollector();
        StandardJavaFileManager standardJavaFileManager = compiler.getStandardFileManager(diagnosticsCollector,
null, null);
        SpecialClassLoader classLoader = new SpecialClassLoader();
        SpecialJavaFileManager fileManager = new SpecialJavaFileManager(standardJavaFileManager,
classLoader);           

        List optionList = new ArrayList();
        optionList.addAll(Arrays.asList("-classpath", System.getProperty("java.class.path")
+ ";" + pathToPackage));

        JavaObjectFromString javaObjectFromString = new JavaObjectFromString(className,
javaFileContents.toString());

        Iterable fileObjects = Arrays.asList(javaObjectFromString);
        Iterable classes = null;           
        Writer out = new PrintWriter(jspOut);

        CompilationTask task = compiler.getTask(out, fileManager, diagnosticsCollector,
optionList, classes, fileObjects);
        Boolean result = task.call();
        List diagnostics = diagnosticsCollector.getDiagnostics();

        if (result) {
            try{
                compiledClass = classLoader.findClass(className);
                Constructor constructor = compiledClass.getConstructor(Writer.class);
                Object instance = constructor.newInstance(jspOut);
                Method instanceMethod = compiledClass.getDeclaredMethod(classMethod,
parameters);
                instanceMethod.invoke(instance, arguments);
            } catch(java.lang.reflect.InvocationTargetException ex) {
                  System.out.println(ex.getCause());
              }
        } else {
            // Compilation fails
            for (Diagnostic d : diagnostics) {
                System.out.println(d);
            }
        }
    }

    private static class JavaObjectFromString extends SimpleJavaFileObject {
        private String sourceCode = null;

        public JavaObjectFromString(String className, String sourceCode) throws Exception {
            super(URI.create("file:///" + className + Kind.SOURCE.extension), Kind.SOURCE);
            this.sourceCode = sourceCode;
        }

        @Override
        public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
            return sourceCode;
        }

        @Override
        public OutputStream openOutputStream() {       
            throw new IllegalStateException();   
        }

        @Override
        public InputStream openInputStream() {       
            return new ByteArrayInputStream(sourceCode.getBytes());   
        }
    }

    private static class JavaObjectFromByteCode extends SimpleJavaFileObject {   
        private ByteArrayOutputStream baos;  

        public JavaObjectFromByteCode(String className) {       
            super(URI.create("byte:///" + className + Kind.CLASS.extension), Kind.CLASS);   
        }

        @Override
        public CharSequence getCharContent(boolean ignoreEncodingErrors) {       
            throw new IllegalStateException();   
        }

        @Override
        public OutputStream openOutputStream() {       
            baos = new ByteArrayOutputStream();       
            return baos;   
        }

        @Override
        public InputStream openInputStream() {       
            throw new IllegalStateException();   
        }

        public byte[] getBytes() {       
            return baos.toByteArray();   
        }
    }

    private static class SpecialClassLoader extends ClassLoader {   
        private Map m = new HashMap();

        protected Class findClass(String className) throws ClassNotFoundException
{       
            JavaObjectFromByteCode jobc = m.get(className);       
            if (jobc==null){           
                jobc = m.get(className.replace(".","/"));           
                if (jobc==null){               
                    return super.findClass(className);           
                }       
            }       
            return defineClass(className, jobc.getBytes(), 0, jobc.getBytes().length);   
        }

        public void addClass(String className, JavaObjectFromByteCode jobc) {       
            m.put(className, jobc);   
        }
    }

    private static class SpecialJavaFileManager extends ForwardingJavaFileManager {   
        private SpecialClassLoader scl;   

        public SpecialJavaFileManager(StandardJavaFileManager sjfm, SpecialClassLoader
scl) {       
            super(sjfm);       
            this.scl = scl;   
        }   

        public JavaFileObject getJavaFileForOutput(Location location, String className,
JavaFileObject.Kind kind, FileObject sibling) throws IOException {       
            JavaObjectFromByteCode jobc = new JavaObjectFromByteCode(className);       
            scl.addClass(className, jobc);       
            return jobc;   
        }

        public ClassLoader getClassLoader(Location location) {       
            return scl;   
        }
    }

}


В дополнение от 15.12.2015 14:56(МСК):

Код класса connector: 

package controller;

import java.util.ArrayList;
import java.util.Hashtable;

import java.util.Iterator;
import java.util.List;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class Connector {
    private static Connector connector = null;
    private static Context context = null;
    private List containers = new ArrayList();

    public Connector() throws NamingException {
        context = getInitialContext();
    }

    public static synchronized Connector getConnector() {
        try {
            if (connector == null) {
                connector = new Connector();
            }
        } catch(Exception ex){
            ex.printStackTrace();
        }
        return connector;
    }

    public synchronized UPContainer getContainerInstance(String session) {
        UPContainer container = new UPContainer();
        boolean has = false;
        try {
            Iterator iterator = containers.iterator();
            while (iterator.hasNext()) {
                UPContainer ch = (UPContainer) iterator.next();
                if (session.equalsIgnoreCase(ch.getSession())) {
                    has = true;
                    container = ch;
                    break;
                }
            }
            if (!has) {
                container.setSession(session);
                container.setControllerInstance((Controller) context.lookup("forum-Controller-Controller#controller.Controller"));
                container.setUserHandlerInstance((userHandler) context.lookup("forum-Controller-userHandler#controller.userHandler"));
                containers.add(container);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return container;
    }

    public synchronized boolean isActive(String userName) {
        try {
            Iterator iterator = containers.iterator();
            while (iterator.hasNext()) {
                UPContainer ch = (UPContainer) iterator.next();
                if (ch.getUserHandlerInstance().getUserCookie() != null)
                    if (userName.equalsIgnoreCase(ch.getUserHandlerInstance().getUserCookie().getValue()))
                        return true;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return false;
    }

    public synchronized void destroyContainerInstance(String session) {
        try {
            Iterator iterator = containers.iterator();
            while (iterator.hasNext()) {
                UPContainer ch = (UPContainer) iterator.next();
                if (session.equalsIgnoreCase(ch.getSession())) {
                    ch.setControllerInstance(null);
                    ch.setUserHandlerInstance(null);
                    containers.remove(ch);
                    break;
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public synchronized int getAmountOfUsersOnline(boolean sm) {
        try {
            if (sm) {
                int counter = 0;
                Iterator iterator = containers.iterator();
                while (iterator.hasNext()) {
                    UPContainer ch = (UPContainer) iterator.next();
                    if (ch.getUserHandlerInstance().getUserCookie() != null)
                        counter++;
                }
                return counter;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return containers.size();
    }

    public synchronized List getOnlineUsers() {
        List usersList = new ArrayList();
        try {
            Iterator iterator = containers.iterator();
            while (iterator.hasNext()) {
                UPContainer ch = (UPContainer) iterator.next();
                if (ch.getUserHandlerInstance().getUserCookie() != null)
                    usersList.add(ch.getUserHandlerInstance().getUserCookie().getValue());
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return usersList;
    }

    private Context getInitialContext() throws NamingException {
        Hashtable env = new Hashtable();
        // WebLogic Server 10.x/12.x connection details
        env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
        env.put(Context.PROVIDER_URL, "t3://127.0.0.1:7101");
        return new InitialContext(env);
    }

}


Дополнение от 15:49:

Код класса pageController:

package controller;

import model.Categories;
import model.Threads;

public class pageController {
    private int topicsPerPage = 15;
    private int viewsPages = 5;
    private int currentPage = 0;
    private int currentAmountPages = 0;
    private int amountPages = 0;
    private int tagCloudlinks = 20;

    public pageController() {
    }

    public void setDefaultTopicsPerPage(int perPage) {
        topicsPerPage = perPage;
    }

    public int getDefaultTopicsPerPage() {
        return topicsPerPage;
    }

    public int getPagesLimit() {
        return viewsPages;
    }

    public void setPagesLimit(int viewsLimit) {
        viewsPages = viewsLimit;
    }

    public int getCurrentPage() {
        return currentPage;
    }

    public void setCurrentPage(String page) {
        currentPage = page != null && page != ""
                    ? Integer.parseInt(page) 
                    : 0;
    }

    public int getCurrentAmountPages() {
        return currentAmountPages;
    }

    public void setCurrentAmountPages(int size) {
        setAmountPages(size);
        currentAmountPages = (int)Math.ceil(new Long(size).doubleValue()/new Long(topicsPerPage).doubleValue());
    }

    public void setAmountPages(int amount) {
        amountPages = amount;
    }

    public int getAmountPages() {
        return amountPages;
    }

    public void setAmountCloudLinks(int amount) {
        tagCloudlinks = amount;
    }

    public int getAmountCloudLinks() {
        return tagCloudlinks;
    }

}


UPDATE

Проблема до сих пор не решена, бессмысленная трата времени доводит меня до безумия,
натыкал пакет controller,с классами, где только можно указал classpath везде где только
можно, но до сих пор возникает ошибка java.lang.NoClassDefFoundError: controller/Connector.

Если создать отдельное приложение с приведенными выше классами то компиляция завершается
успешно System.out.println(Connector.class); выводит класс коннектор, как и было нужно,
но если запускать через JSP, то возникает выше описанная проблема

Смысл всей этой затеи: запрос к БД за кодом(Java,PHP,HTML) -> парсинг всего этого
дела-> в JSP вызов компиляции -> готовый HTML код в JSP
    


Ответы

Ответ 1



Причина возникновения ошибки NoClassDefFoundError сильно варьируется, те за первопричиной возникновения ее скрыт ряд проблем. В моем же случае ошибка связана с повторной загрузкой класса загрузчиками классов и областью видимости другими загрузчиками классов(см иерархия загрузчиков классов), те один из загрузчиков пытается найти на своем уровне нужный класс, но не находит его здесь, и делегирует запрос на вышестоящий загрузчик(см делегирование запросов), далее на вышестоящем уровне происходит подгрузка необходимого класса, но с другой стороны необходимый класс подгужается другим загрузчиком(не имеющим отношений с предыдущим) при компилиции класса(из строкового представления см StringBuilder класс CompiledClass) и в происходит генерация ошибки(сигнализация что класс не найден). Конкретно: в jsp(Web App) происходит подгрузка классов, но так как они не известны на этом уровне загрузчиков, то загрузчик на этом уровне делегирует загрузку на выше стоящие уровни загрузчиков и в последствии происходит загрузка на Java EE App(где определены классы) уровне. С др стороны подгрузка происходит на др уровне при компилиции класса CompiledClass и возникает ошибка. Те два загрузчика(несвязные) загружают одни и те же классы. Почему компилируется успешно в отдельном приложении? Как описывал выше компиляция в этом случае успешна. Почему? Ответ: классы подгружаются только одним загрузчиком и никаких исключений соотв при этом не возникает. Просьба не редактировать это сообщение тк проблему решил не до конца(пока не решил) в последствии дам более точный конкретный ответ. Как вариант можно попробовать рефлексию(пока не проверял) в компилируемом классе(из строкового представления), но есть одно но, понятно что при увеличении "сложности" класса придется прописывать прописывать обращения множеством строк кода, по-этому этот вариант не совсем подходит.