How to get "Delegation Pattern for Sling Models" working? - aem

I'm trying to create a proxy component for AEM Core Component with custom Sling Model which delegates part of functionality back to the Core Component's Sling Model.
I'm following the example from https://github.com/adobe/aem-core-wcm-components/wiki/Delegation-Pattern-for-Sling-Models but it results in java.lang.IllegalArgumentException: Can not set com.example.core.models.Title field.
Setup
AEM version 6.4.4
core.wcm.components.content version 2.4.0
Sources
/apps/myproject/components/pageHeadline/.content.xml
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="cq:Component"
jcr:title="Page Headline"
jcr:description="Display Page Heading"
sling:resourceSuperType="core/wcm/components/title/v2/title"
componentGroup="My Project"/>
com.example.core.models.PageHeadline
package com.example.core.models;
import com.adobe.cq.wcm.core.components.models.Title;
import com.day.cq.wcm.api.Page;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.Via;
import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;
import org.apache.sling.models.annotations.injectorspecific.Self;
import org.apache.sling.models.annotations.via.ResourceSuperType;
#Model(adaptables = SlingHttpServletRequest.class, adapters = Title.class, resourceType = "myproject/components/pageHeadline")
public class PageHeadline implements Title {
#ScriptVariable
private Page currentPage;
#Self #Via(type = ResourceSuperType.class)
private Title delegate;
#Override
public String getText() {
return currentPage.getTitle();
}
#Override
public String getType() {
return delegate.getType();
}
}
Result
org.apache.sling.api.SlingException: Cannot get DefaultSlingScript: Identifier com.example.core.models.Title cannot be correctly instantiated by the Use API
...
Caused by: org.apache.sling.scripting.sightly.SightlyException: Identifier com.example.core.models.Title cannot be correctly instantiated by the Use API
at org.apache.sling.scripting.sightly.impl.engine.extension.use.UseRuntimeExtension.call(UseRuntimeExtension.java:78) [org.apache.sling.scripting.sightly:1.0.54.1_4_0]
at org.apache.sling.scripting.sightly.impl.engine.runtime.RenderContextImpl.call(RenderContextImpl.java:69) [org.apache.sling.scripting.sightly:1.0.54.1_4_0]
at org.apache.sling.scripting.sightly.apps.core.wcm.components.title.v2.title.title_html.render(title_html.java:41)
at org.apache.sling.scripting.sightly.java.compiler.RenderUnit.render(RenderUnit.java:48) [org.apache.sling.scripting.sightly.compiler.java:1.0.26.1_4_0]
at org.apache.sling.scripting.sightly.impl.engine.SightlyCompiledScript.eval(SightlyCompiledScript.java:61) [org.apache.sling.scripting.sightly:1.0.54.1_4_0]
at org.apache.sling.scripting.core.impl.DefaultSlingScript.call(DefaultSlingScript.java:386) [org.apache.sling.scripting.core:2.0.54]
at org.apache.sling.scripting.core.impl.DefaultSlingScript.eval(DefaultSlingScript.java:184) [org.apache.sling.scripting.core:2.0.54]
at org.apache.sling.scripting.core.impl.DefaultSlingScript.service(DefaultSlingScript.java:491) [org.apache.sling.scripting.core:2.0.54]
... 269 common frames omitted
Caused by: org.apache.sling.models.factory.MissingElementsException: Could not inject all required fields into class com.example.core.models.PageHeadline
at org.apache.sling.models.impl.ModelAdapterFactory.createObject(ModelAdapterFactory.java:765) [org.apache.sling.models.impl:1.4.10]
at org.apache.sling.models.impl.ModelAdapterFactory.internalCreateModel(ModelAdapterFactory.java:448) [org.apache.sling.models.impl:1.4.10]
at org.apache.sling.models.impl.ModelAdapterFactory.createModel(ModelAdapterFactory.java:314) [org.apache.sling.models.impl:1.4.10]
at org.apache.sling.scripting.sightly.models.impl.SlingModelsUseProvider.provide(SlingModelsUseProvider.java:126) [org.apache.sling.scripting.sightly.models.provider:1.0.6]
at org.apache.sling.scripting.sightly.impl.engine.extension.use.UseRuntimeExtension.call(UseRuntimeExtension.java:73) [org.apache.sling.scripting.sightly:1.0.54.1_4_0]
... 276 common frames omitted
Suppressed: org.apache.sling.models.factory.MissingElementException: Could not inject private com.example.core.models.Title com.example.core.models.PageHeadline.title
at org.apache.sling.models.impl.ModelAdapterFactory.createObject(ModelAdapterFactory.java:749) [org.apache.sling.models.impl:1.4.10]
... 280 common frames omitted
Caused by: org.apache.sling.models.factory.ModelClassException: Could not inject field due to reflection issues
at org.apache.sling.models.impl.model.InjectableField.set(InjectableField.java:48) [org.apache.sling.models.impl:1.4.10]
at org.apache.sling.models.impl.ModelAdapterFactory.setField(ModelAdapterFactory.java:989) [org.apache.sling.models.impl:1.4.10]
at org.apache.sling.models.impl.ModelAdapterFactory.access$200(ModelAdapterFactory.java:132) [org.apache.sling.models.impl:1.4.10]
at org.apache.sling.models.impl.ModelAdapterFactory$SetFieldCallback.inject(ModelAdapterFactory.java:500) [org.apache.sling.models.impl:1.4.10]
at org.apache.sling.models.impl.ModelAdapterFactory.injectElement(ModelAdapterFactory.java:595) [org.apache.sling.models.impl:1.4.10]
at org.apache.sling.models.impl.ModelAdapterFactory.createObject(ModelAdapterFactory.java:744) [org.apache.sling.models.impl:1.4.10]
... 280 common frames omitted
Caused by: java.lang.IllegalArgumentException: Can not set com.example.core.models.Title field com.example.core.models.PageHeadline.title to com.adobe.cq.wcm.core.components.internal.models.v1.TitleImpl
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
at java.lang.reflect.Field.set(Field.java:764)
at org.apache.sling.models.impl.model.InjectableField.set(InjectableField.java:46) [org.apache.sling.models.impl:1.4.10]
... 285 common frames omitted

I had the same problem, where the delegation pattern was not working, specifically, the injected attribute was null if I used #Optional, or the same stack trace as posted if #Optional was left out.
The problem for me was that we are using the following Embed-Dependency code:
<Embed-Dependency>
*;scope=compile|runtime
</Embed-Dependency>
<Embed-Transitive>true</Embed-Transitive>
in the maven-bundle-plugin. The issue was that the core components dependency got set as an embedded dependency. Once I fixed this, the delegation pattern worked fine.
<Embed-Dependency>
*;scope=compile|runtime;artifactId=!core.wcm.components.core
</Embed-Dependency>

Related

Write/Run Junit Test class (To test actuators) without Datasource bean creation in springboot container

What we are trying to do?
Writing a Junit for Springboot actuator/Admin as below
Code snippet:
ActuatorTests.java
#SpringBootTest(properties = {
"management.endpoints.web.exposure.include=" })
#ActiveProfiles(profiles = "local")
#AutoConfigureMockMvc
public class ActuatorTests {
#Autowired
private MockMvc mockMvc;
#MockBean
JwtDecoder jwtDecoder;
#Test
public void testActuatorEndpointSuccess() throws Exception {
MockHttpServletResponse resp = mockMvc
.perform(MockMvcRequestBuilders.get("/actuator/").accept(MediaType.APPLICATION_JSON)).andReturn()
.getResponse();
assertEquals(resp.getStatus(), 200);
}
application-local.yml
This property contains Datasource, username, password and others properties
What is the issue?
During spring boot container start, it is creating Data Source by using data source properties of application-local.yml
Problem here is I can't rely on application-local.yml becoz properties changes environment to environment may not work all the time with same property values and also which is unnecessary for my Junit as the testcase is about testing the management actuator endpoint only.
What we have tried?
Ran by excluding some the JPA classes using below.
#SpringBootTest(properties = {
"management.endpoints.web.exposure.include=" })
#ActiveProfiles(profiles = "local")
#AutoConfigureMockMvc
#EnableAutoConfiguration(exclude = {
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class
})
public class ActuatorTests { .....}
But found the below error in the console.
Note: the error log also having chain of bean creation errors from DAO,Service, to Controller layer classes,
I have given only the tail of the log due to restrictions.
**Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available**
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:805)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1278)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:297)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:276)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330)
... 118 common frames omitted
Any help on this?
We can see similar question has been asked but no answer found in it.
Run junit without data source persistence context in spring boot
Any other solution to above actuator Test Junit is also welcome..

Error while loading a tagger model (probably missing model file)

I am trying to implement the below code:
import java.util.Properties;
import edu.stanford.nlp.coref.CorefCoreAnnotations;
import edu.stanford.nlp.coref.CorefCoreAnnotations;
import edu.stanford.nlp.coref.data.CorefChain;
import edu.stanford.nlp.coref.data.Mention;
import edu.stanford.nlp.ling.CoreAnnotations;
import edu.stanford.nlp.pipeline.Annotation;
import edu.stanford.nlp.pipeline.StanfordCoreNLP;
import edu.stanford.nlp.util.CoreMap;
public class CorefResolver {
public static void main(String[] args) throws Exception {
Annotation document = new Annotation("Barack Obama was born in Hawaii. He is the president. Obama was elected in 2008.");
Properties props = new Properties();
props.setProperty("annotators", "tokenize,ssplit,pos,lemma,ner,parse,mention,coref");
StanfordCoreNLP pipeline = new StanfordCoreNLP(props);
pipeline.annotate(document);
System.out.println("---");
System.out.println("coref chains");
for (CorefChain cc : document.get(CorefCoreAnnotations.CorefChainAnnotation.class).values()) {
System.out.println("\t" + cc);
}
for (CoreMap sentence : document.get(CoreAnnotations.SentencesAnnotation.class)) {
System.out.println("---");
System.out.println("mentions");
for (Mention m : sentence.get(CorefCoreAnnotations.CorefMentionsAnnotation.class)) {
System.out.println("\t" + m);
}
}
}
}
This is a code from stanford corenlp. I have used eclipse as framework. Below image shows the view in eclipse.
While running the code, I am getting the below error. I have tried including models taggers etc. Still showing the same error.
Adding annotator tokenize
No tokenizer type provided. Defaulting to PTBTokenizer.
Adding annotator ssplit
Adding annotator pos
Exception in thread "main" java.lang.RuntimeException: edu.stanford.nlp.io.RuntimeIOException: Error while loading a tagger model (probably missing model file)
at edu.stanford.nlp.pipeline.AnnotatorFactories$4.create(AnnotatorFactories.java:245)
at edu.stanford.nlp.pipeline.AnnotatorPool.get(AnnotatorPool.java:152)
at edu.stanford.nlp.pipeline.StanfordCoreNLP.construct(StanfordCoreNLP.java:451)
at edu.stanford.nlp.pipeline.StanfordCoreNLP.<init>(StanfordCoreNLP.java:154)
at edu.stanford.nlp.pipeline.StanfordCoreNLP.<init>(StanfordCoreNLP.java:150)
at edu.stanford.nlp.pipeline.StanfordCoreNLP.<init>(StanfordCoreNLP.java:137)
at CorefResolver.main(CorefResolver.java:16)
Caused by: edu.stanford.nlp.io.RuntimeIOException: Error while loading a tagger model (probably missing model file)
at edu.stanford.nlp.tagger.maxent.MaxentTagger.readModelAndInit(MaxentTagger.java:791)
at edu.stanford.nlp.tagger.maxent.MaxentTagger.<init>(MaxentTagger.java:312)
at edu.stanford.nlp.tagger.maxent.MaxentTagger.<init>(MaxentTagger.java:265)
at edu.stanford.nlp.pipeline.POSTaggerAnnotator.loadModel(POSTaggerAnnotator.java:85)
at edu.stanford.nlp.pipeline.POSTaggerAnnotator.<init>(POSTaggerAnnotator.java:73)
at edu.stanford.nlp.pipeline.AnnotatorImplementations.posTagger(AnnotatorImplementations.java:63)
at edu.stanford.nlp.pipeline.AnnotatorFactories$4.create(AnnotatorFactories.java:243)
... 6 more
Caused by: java.io.IOException: Unable to open "edu/stanford/nlp/models/pos-tagger/english-left3words/english-left3words-distsim.tagger" as class path, filename or URL
at edu.stanford.nlp.io.IOUtils.getInputStreamFromURLOrClasspathOrFileSystem(IOUtils.java:470)
at edu.stanford.nlp.tagger.maxent.MaxentTagger.readModelAndInit(MaxentTagger.java:789)
... 12 more
Could anyone help me to solve this issue?
Using Kotlin Gradle dsl (build.gradle.kts) this worked for me:
val corenlp_version = "4.2.2"
If you don't want to use the previous variable, you can substitute the value:
implementation("edu.stanford.nlp:stanford-corenlp:$corenlp_version")
implementation("edu.stanford.nlp:stanford-corenlp:$corenlp_version:models")
implementation("edu.stanford.nlp:stanford-corenlp:$corenlp_version:models-english")
implementation("edu.stanford.nlp:stanford-corenlp:$corenlp_version:models-english-kbp")
Included Stanford corenlp 3.8 jar and Stanford corenlp 3.8 models. Now the coreference resolution is working
jar
I found adding the models classifier dependency worked.
<dependency>
<groupId>edu.stanford.nlp</groupId>
<artifactId>stanford-corenlp</artifactId>
<version>4.2.2</version>
</dependency>
<dependency>
<groupId>edu.stanford.nlp</groupId>
<artifactId>stanford-corenlp</artifactId>
<version>4.2.2</version>
<classifier>models</classifier>
</dependency>

JPA static metamodel classes in EclipseLink throw NullPointerException when accessing attributes

I have a problem with generated static metamodel classes in EclipseLink.
In my project I firstly generated static metamodel classed for my entities using:
1) org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor and IntelliJ IDEA
and this classes have been generated to: target/generated-sources
Then I try to use such Hibernate generated metamodel classes (ex. below) with EclipseLink (GlassFish embedded), but lines of code that contains references to metamodel attributes throws NullPointerException exception:
SingularAttribute<Employee, String> descriptionAttr = Employee_.description;
predicates.add(criteriaBuilder.like(employee.get(descriptionAttr), "%" + description + "%"));
Here emploee.get( >> null << ) throws exception.
#Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
#StaticMetamodel(Employee.class)
public abstract class Employee_ extends pl.salonea.entities.NaturalPerson_ {
public static volatile SetAttribute<Employee, Skill> skills;
public static volatile SetAttribute<Employee, ProviderService> suppliedServices;
public static volatile SetAttribute<Employee, EmployeeRating> receivedRatings;
public static volatile SingularAttribute<Employee, String> description;
public static volatile SetAttribute<Employee, Education> educations;
public static volatile SingularAttribute<Employee, String> jobPosition;
public static volatile SetAttribute<Employee, TermEmployeeWorkOn> termsOnWorkStation;
}
2) Next I thought that this metamodel classes maybe are implementation specific. So I generated them analogically with EclipseLink using
org.eclipse.persistence.internal.jpa.modelgen.CanonicalModelProcessor and target/generated-sources-eclipselink (as on picture)
At the end I have something like this directory stracture with metamodel:
3) I am also using in build.gradle such configuration to as I think include this generated sources in project:
if(hasProperty('jboss')) {
sourceSets {
main {
java {
srcDir 'target/generated-sources/'
}
}
}
} else {
sourceSets {
main {
java {
srcDir 'target/generated-sources-eclipselink/'
}
}
}
}
This way I want to use Hibernate generated classes with Jboss and EclipseLink generated classes with EclipseLink.
4) Such configuration works only if running on WilfFly/Hibernate but not on GlassFish/EclipseLink here is this NullPointerException
5) In persistence.xml I have more over EclipseLink generation using such property for one Persistence Unit
<property name="eclipselink.canonicalmodel.subpackage" value="metamodel" />
and such property for second Persistence Unit (to avoid duplicate conflict)
<property name="eclipselink.canonicalmodel.subpackage" value="metamodel_local" />
But I'm trying not to use this generation. It is in subpackage and in my code I only import previously generated metamodel classes.
The reason is that I would like to have in the same namespace metamodel classes generated by Hibernate/Eclipse and use them appropriately.
However if Hibernate generated metamodel classes could be also work with EclipseLink there won't be problem to using only one generation.
6) Moreover I cant use metamodel classes generated by EclipseLink persistence.xml property as they are regenerated each time I run/build my project. And I need in my code to manually modify two metamodel classes as they are inherited from single abstract metamodel class. Here I am overriding in subclasses AbstractType with ConcreteType on SetAttribute of metamodel class.
7) At the end I paste error I'm getting while running integration test with such configuration of metamodel classes
Caused by: java.lang.NullPointerException
at org.eclipse.persistence.internal.jpa.querydef.FromImpl.get(FromImpl.java:263)
at pl.salonea.ejb.stateless.EmployeeFacade.findByMultipleCriteria(EmployeeFacade.java:295)
at pl.salonea.ejb.stateless.EmployeeFacade.findByMultipleCriteria(EmployeeFacade.java:269)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.glassfish.ejb.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1081)
at org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManager.java:1153)
at com.sun.ejb.containers.BaseContainer.invokeBeanMethod(BaseContainer.java:4786)
at com.sun.ejb.EjbInvocation.invokeBeanMethod(EjbInvocation.java:656)
at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:822)
at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:608)
at org.jboss.weld.ejb.AbstractEJBRequestScopeActivationInterceptor.aroundInvoke(AbstractEJBRequestScopeActivationInterceptor.java:46)
at org.jboss.weld.ejb.SessionBeanInterceptor.aroundInvoke(SessionBeanInterceptor.java:52)
at sun.reflect.GeneratedMethodAccessor113.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:883)
at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:822)
at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:608)
at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doCall(SystemInterceptorProxy.java:163)
at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.aroundInvoke(SystemInterceptorProxy.java:140)
at sun.reflect.GeneratedMethodAccessor141.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:883)
at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:822)
at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:369)
at com.sun.ejb.containers.BaseContainer.__intercept(BaseContainer.java:4758)
at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:4746)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:212)
... 149 more
-I'm checking EclipseLink sources:
public <Y> Path<Y> get(SingularAttribute<? super X, Y> att){
if (att.getPersistentAttributeType().equals(
PersistentAttributeType.BASIC)) {
return new PathImpl<Y>(
this, this.metamodel, att.getBindableJavaType(),
this.currentNode.get(att.getName()), att);
} else {
Class<Y> clazz = att.getBindableJavaType();
Join join = new JoinImpl<X, Y>(
this, this.metamodel.managedType(clazz),
this.metamodel, clazz,
this.currentNode.get(att.getName()), att);
this.joins.add(join);
return join;
}
}
FromImpl.java:263 is condition of if statement so it looks like att.getPersistentAttributeType() returns null.
It would be good if you'll file a bug against EclipseLink on https://bugs.eclipse.org/bugs/enter_bug.cgi?product=EclipseLink
Component is JPA. Please copy-paste this description there and provide some test-case (sample application with this metamodel) to let us reproduce it and develop some fix.
The problem can be in the failed initialization Canonical Metamodel.
You can investigate yours eclipselink log for checking something like that:
Could not load the field named [...] on the class [...]
IllegalArgumentException: Can not set static ... field ... to ...
In my case after fixing initialization, NPE had gone.
I know this is an old ticket but i still wanted to let you guys know how we fixed the problem. Especially the last nullpointer exception.
The problem is that your entitimanager is not loaded when you are using your Criteriabuilder for the first time.
To solve this problem you can set following in you persistence.xml
<property name="eclipselink.deploy-on-startup" value="true" />

Spring bean loading issue in BIRT designer

I have an issue with Spring not loading beans correctly when run from a script in a BIRT Scripted Data Source, but running OK on its own.
Here's a minimal test case:
The spring bean:
package test;
import org.springframework.stereotype.Component;
#Component
public class TestComponent { }
The context provider:
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringContextHolder {
private static ApplicationContext ac;
public static ApplicationContext getApplicationContext() {
if( ac == null ) {
ac = new ClassPathXmlApplicationContext("classpath:beans.xml");
}
return ac;
}
}
beans.xml:
<beans .......>
<context:component-scan base-package="test"></context:component-scan>
<context:annotation-config />
</beans>
And finally the test program which is a simple Eclipse java project having all spring and related jars and the test.jar from above in its build path:
public class cltest {
public static void main(String[] args ) throws BeansException {
System.out.println(test.SpringContextHolder.getApplicationContext().getBean("testComponent"));
}
}
This program runs fine and delivers the bean. But when I run the same jars in BIRT designer (4.3.0) by setting them in the Report classpath preferences, I get an exception:
A BIRT exception occurred. See next exception for more information.
Wrapped org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidate component class: URL [jar:file:/C:/Users/xxx/.m2/repository/test/test/0.0.1-SNAPSHOT/test-0.0.1-SNAPSHOT.jar!/test/SpringContextHolder.class]; nested exception is java.lang.ArrayIndexOutOfBoundsException: 6
The script source is simply:
importPackage(Packages.test);
ts = SpringContextHolder.getApplicationContext().getBean("testComponent");
The exception results from org.springframework.asm.ClassReader where a readShort violates some array boundaries.
Spring version is 3.2.3 RELEASE, Oracle Java 7u25, BIRT Designer 4.3.0.
Can anyone explain what the difference between the two running scenarios is? Probably some class loader issues when the jars are loaded by the eclipse runtime?

Loading classes using Spring inside an eclipse OSGi container does not seem to work. Fix?

I am somewhat puzzled about Spring's classloading behavior inside an eclipse OSGi container (which is the basis for the TIBCO ActiveMatrix runtime I am trying to get this running on) and boiled this down to the below simple example.
In it (the TestComponent object is created and called inside an OSGi bundle's Activator class, but I don't think that this is important here) I first create an object direcly, just to double-check, that its class exists and can be instantiated. This of course works as one would expect...
Second, I want to create a second object of that very same class using Spring (as I originally intended), but this fails with a ClassNotFoundException.
Spring claims, it can't find that class (even though the package and class name definitely match), so I even added a .setClassLoader(...) call to pass it the very same classloader that just successfully loaded that very same class, but Spring still fails to locate that class.
Any clue of why that is so? I have ran out of ideas. What am I missing?
Later edit: I just had to realize, that it is NOT the ...getBean(...)-method call that crashes, but rather already the ClassPathXmlApplicationContext()-constructor. I.e. the object is already created in that constructor and not only later in the subsequent getBean(...)-method call. Thus my attempt to pass-in the classloader is futile as it already comes to late. So the question thus rather is: how can I pass-in the context's class loader to that constructor (or to the factory or whatever Spring uses internally to create the ClassPathXmlApplicationContext object)?
My example:
I first defined an interface for the class to be created via Spring:
package com.example.some_package_0;
public interface SomeInterface
{
public String getSomeString();
}
... and a class, implementing this interface:
package com.example.some_package_1;
import com.example.some_package_0.SomeInterface;
public class SomeClassA implements SomeInterface
{
private String someProperty;
public void setSomeProperty(String someProperty) {
this.someProperty = someProperty;
}
public String getSomeString() {
return this.someProperty;
}
}
My Test-program reads
public class TestComponent
{
import com.example.some_package_0.SomeInterface;
import com.example.some_package_1.SomeClassA;
public void test() {
SomeClassA obj1 = new SomeClassA();
obj1.setSomeProperty("SomeClassA-object (directly created)");
System.out.println("## message=\"" + obj1.getSomeString() + "\"");
ClassPathXmlApplicationContext applicationContext;
applicationContext = new ClassPathXmlApplicationContext("/META-INF/package1_beans.xml");
applicationContext.setClassLoader(Thread.currentThread().getContextClassLoader());
SomeInterface obj2 = (SomeInterface) applicationContext.getBean("bean1");
System.out.println("## message=\"" + obj2.getSomeString() + "\"");
}
}
The /META-INF/package1_beans.xml being used reads:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans classpath:/org/springframework/beans/factory/xml/spring-beans-2.5.xsd">
<bean id="bean1" class="com.example.some_package_1.SomeClassA">
<property name="someProperty"><value>SomeClassA-object (created via Spring)</value></property>
</bean>
</beans>
The exception reads:
org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [com.example.some_package_1.SomeClassA] for bean with name 'bean1' defined in class path resource [META-INF/package1_beans.xml]; nested exception is java.lang.ClassNotFoundException: com.example.some_package_1.SomeClassA
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1141)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:524)
at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1177)
at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:758)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:422)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:728)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:380)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at com.example.test_spring_example.TestComponent.testOperation(TestComponent.java:71)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.tibco.amf.platform.runtime.componentframework.internal.proxies.operation.OperationHandler.invokeMethodWithThreadContext(OperationHandler.java:667)
at com.tibco.amf.platform.runtime.componentframework.internal.proxies.operation.AsyncToSyncOperationHandler.invoke(AsyncToSyncOperationHandler.java:98)
at com.tibco.amf.platform.runtime.componentframework.internal.proxies.ProxyInvocationHandlerRegistry$ProxyInvocationContext.invoke(ProxyInvocationHandlerRegistry.java:411)
at $Proxy67.invoke(Unknown Source)
at com.tibco.amf.binding.soap.runtime.transport.http.SoapHttpInboundEndpoint.processHttpPost(SoapHttpInboundEndpoint.java:565)
at com.tibco.amf.binding.soap.runtime.transport.http.SoapHttpServer.doPost(SoapHttpServer.java:195)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:502)
at org.mortbay.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1213)
at com.tibco.governance.pa.amxcomponent.pep.http.HttpPepFilter.doFilter(HttpPepFilter.java:126)
at org.mortbay.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1205)
at com.tibco.amf.implementation.common.httpfilter.GenericComponentFilter.doFilter(GenericComponentFilter.java:65)
at org.mortbay.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1205)
at com.tibco.amf.hpa.tibcohost.jetty.internal.ConnectorFilter.doFilter(ConnectorFilter.java:49)
at org.mortbay.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1205)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230)
at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:536)
at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:928)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:747)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:405)
at org.mortbay.jetty.bio.SocketConnector$Connection.run(SocketConnector.java:228)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.ClassNotFoundException: com.example.some_package_1.SomeClassA
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:513)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:429)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:417)
at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:107)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at org.springframework.util.ClassUtils.forName(ClassUtils.java:211)
at org.springframework.beans.factory.support.AbstractBeanDefinition.resolveBeanClass(AbstractBeanDefinition.java:385)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1138)
... 46 more
Actually, the solution turned out to be almost trivial!
As I already stated in my comment to #Robin apparently in OSGi the current thread's classloader and the current context or class' classloader are not the same!
So, all I had to do in the end was to set the current thread's context-classloader to the calling object's classloader and that's it! I.e. one doesn't even need to dig into OSGi to obtain the bundle's class loader or fiddle with manifests or POMs or anything like that - just tell Spring to use "my" own class' classloader and off you go!
...
// need to set the context class loader to "my" class loader to make Spring work:
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
ClassPathXmlApplicationContext applicationContext;
applicationContext =
new ClassPathXmlApplicationContext("/META-INF/package1_beans.xml");
SomeInterface obj2 = (SomeInterface) applicationContext.getBean("bean1");
System.out.println("## message=\"" + obj2.getSomeString() + "\"");
...
And - yes - one probably should set the thread's class loader back to the original value after that, just in case - so another good used for a try { ... } finally { ... } clause. :-)
Thanks all for responding!
M.
I have one other idea.
Instead of initializing your Spring context manually. Try adding this to your pom.xml (if you are using Maven):
<configuration>
<instructions>
<Spring-Context>spring/*.xml</Spring-Context>
Make it point to the location of your applContext. This seems a neater way to hook it up as well. If you are not using Maven youll need to add manually to the Manifest, Im not sure exactly the right syntax for that