Używam agenta Freemarker i DCEVM + HotSwapManager. Zasadniczo pozwala mi to na klasy hotswap nawet przy dodawaniu/usuwaniu metod.Freemarker removeIntrospectionInfo nie działa z DCEVM po modelu hotswap
Wszystko działa jak czar, dopóki Freemarker nie użyje klasy hotswapped jako modelu. Rzucanie freemarker.ext.beans.InvalidPropertyException: Brak takiej właściwości komponentu bean, nawet jeśli odbicie pokazuje, że metoda istnieje (zaznaczona podczas sesji debugowania).
Używam
final Method clearInfoMethod = beanWrapper.getClass().getDeclaredMethod("removeIntrospectionInfo", Class.class);
clearInfoMethod.setAccessible(true);
clearInfoMethod.invoke(clazz);
wyczyścić pamięć podręczną, ale to nie działa. Próbowałem nawet uzyskać pole członkowskie classCache i wyczyścić je za pomocą refleksji, ale to też nie działa.
Co robię źle? Po prostu muszę zmusić freemarkera do wyrzucenia introspekcji na klasę/klasę modelu, którą już zdobył.
Czy jest jakiś sposób?
UPDATE
przykład kod
Application.java
// Application.java
public class Application
{
public static final String TEMPLATE_PATH = "TemplatePath";
public static final String DEFAULT_TEMPLATE_PATH = "./";
private static Application INSTANCE;
private Configuration freemarkerConfiguration;
private BeansWrapper beanWrapper;
public static void main(String[] args)
{
final Application application = new Application();
INSTANCE = application;
try
{
application.run(args);
}
catch (InterruptedException e)
{
System.out.println("Exiting");
}
catch (IOException e)
{
System.out.println("IO Error");
e.printStackTrace();
}
}
public Configuration getFreemarkerConfiguration()
{
return freemarkerConfiguration;
}
public static Application getInstance()
{
return INSTANCE;
}
private void run(String[] args) throws InterruptedException, IOException
{
final String templatePath = System.getProperty(TEMPLATE_PATH) != null
? System.getProperty(TEMPLATE_PATH)
: DEFAULT_TEMPLATE_PATH;
final Configuration configuration = new Configuration();
freemarkerConfiguration = configuration;
beanWrapper = new BeansWrapper();
beanWrapper.setUseCache(false);
configuration.setObjectWrapper(beanWrapper);
try
{
final File templateDir = new File(templatePath);
configuration.setTemplateLoader(new FileTemplateLoader(templateDir));
}
catch (IOException e)
{
throw new RuntimeException(e);
}
final RunnerImpl runner = new RunnerImpl();
try
{
runner.run(args);
}
catch (RuntimeException e)
{
e.printStackTrace();
}
}
public BeansWrapper getBeanWrapper()
{
return beanWrapper;
}
}
RunnerImpl.java
// RunnerImpl.java
public class RunnerImpl implements Runner
{
@Override
public void run(String[] args) throws InterruptedException
{
long counter = 0;
while(true)
{
++counter;
System.out.printf("Run %d\n", counter);
// Application.getInstance().getFreemarkerConfiguration().setObjectWrapper(new BeansWrapper());
Application.getInstance().getBeanWrapper().clearClassIntrospecitonCache();
final Worker worker = new Worker();
worker.doWork();
Thread.sleep(1000);
}
}
Worker.java
// Worker.java
public class Worker
{
void doWork()
{
final Application application = Application.getInstance();
final Configuration freemarkerConfiguration = application.getFreemarkerConfiguration();
try
{
final Template template = freemarkerConfiguration.getTemplate("test.ftl");
final Model model = new Model();
final PrintWriter printWriter = new PrintWriter(System.out);
printObjectInto(model);
System.out.println("-----TEMPLATE MACRO PROCESSING-----");
template.process(model, printWriter);
System.out.println();
System.out.println("-----END OF PROCESSING------");
System.out.println();
}
catch (IOException e)
{
e.printStackTrace();
}
catch (TemplateException e)
{
e.printStackTrace();
}
}
private void printObjectInto(Object o)
{
final Class<?> aClass = o.getClass();
final Method[] methods = aClass.getDeclaredMethods();
for (final Method method : methods)
{
System.out.println(String.format("Method name: %s, public: %s", method.getName(), Modifier.isPublic(method.getModifiers())));
}
}
}
Model.java
// Model.java
public class Model
{
public String getMessage()
{
return "Hello";
}
public String getAnotherMessage()
{
return "Hello World!";
}
}
Przykład ten nie działa w ogóle. Nawet zmiana BeansWrapper podczas działania nie będzie miała żadnego efektu.
Zakładając, że wywołasz metodę na 'BeansWrapper', która jest aktualnie używana, powinna działać. Ale 'removeFromClassIntrospectionCache (Class clazz)' jest metodą publiczną, dlaczego tak ją nazywasz? Jeśli jest to stary FreeMarker, spróbuj najpierw aktualizacji. – ddekany
@ddany: Mam do czynienia z tym samym problemem co Martin. Używam wersji 2.3.19, więc uaktualnienie powinno wystarczyć. Jednak komentarz Javadoc do 'removeFromClassIntrospectionCache' zadaje mi pytania:" '... Jeśli klasa będzie nadal używana, wpis w pamięci podręcznej zostanie cicho odtworzony" "- oznacza to, że gdy pamięć podręczna szablonu zawiera mapowanie dla klasy pytanie, czy introspekcja nie dostanie jej przeładowanej wersji? Dzięki! – plesatejvlk
Czyściłem jedyną BeansWrapper, którą ustawiłem na obiekt konfiguracji freemarkera. Zobacz aktualizację na przykładzie. –