SlingModel still returning null when adapting item - aem

I am trying to get Sling Models working.
I have a simple annotated POJO that maps to a JCR Node by convention as follows:
#Model(adaptables=Resource.class)
public class FlushRule {
#Inject
public String optingRegex;
}
I have set a String value in optingRegex.
When I try to use it:
FlushRule currentRule=rule.adaptTo(FlushRule.class);
Although the correct object is in rule, currentRule is null.
I looked in
http://localhost:4502/system/console/adapters
and couldn't find any adapters.
Any tips would be appreciated.

You need to add following lines to the maven-bundle-plugin configuration in your pom.xml:
<configuration>
<instructions>
<Sling-Model-Packages>
org.apache.sling.models.it.models
</Sling-Model-Packages>
</instructions>
</configuration>
where org.apache.sling.models.it.models is the Java package containing your models. The configured package (and all its subpackages) will be scanned for #Models. More information can be found on the Sling website.

Another reason why the Sling Model object could be null is when the Sling Model has a parameterised constructor and no default constructor.
Example:
#Model(adaptables = Resource.class)
public class CompetitionRound {
#Inject
String round;
public CompetitionRound(String round) {
this.round = round;
}
}
Add a default constructor and it should work.
#Model(adaptables = Resource.class)
public class CompetitionRound {
#Inject
String round;
public CompetitionRound() {
}
public CompetitionRound(String round) {
this.round = round;
}
}

Related

spring aop with custom annotation on mybatis dao's methods, parameterNames is null

In my project with spring boot 2.1.3.RELEASE,
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
I have created a custom annotation:
#Target({ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Inherited
public #interface MyAnnotation {
}
and this is mybatis dao:
#Component
#Mapper
public interface MyOrderDao {
#MyAnnotation
List<MyOrder> findBySerialNo(String orderNo);
}
and this is my aspect:
#Aspect
#Component
public class MyAspect {
#Pointcut(value = "#annotation(MyAnnotation)")
public void pointCut() {
}
#Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
String [] parameterNames = methodSignature.getParameterNames();
// TODO
return joinPoint.proceed();
}
}
and I get parameterNames is null,
but i put the annotation on a class's method instead of a interface, i get parameterNames correctly.like this:
#Service
public class MyOrderService {
#Autowired
private MyOrderDao myOrderDao;
#MyAnnotation
public MyOrder getOrderBySerialNo(String serialNo) {
if (StringUtils.isBlank(serialNo)) {
return null;
}
List<MyOrder> orders = myOrderDao.findBySerialNo(serialNo);
if (orders != null && !orders.isEmpty()) {
return orders.get(0);
}
return null;
}
}
so, how can i get parameterNames correctly for mybatis dao ?
please help me, thanks a lot.
This one is a classic: You are assuming that just because you made your annotation #Inherited, it will be inherited by implementing classes if you annotate interface methods. But this assumption is wrong. #Inherited only works in exactly one case: when extending an annotated base class. It does not work for annotated interfaces, methods etc. This is also documented here:
Note that this meta-annotation type has no effect if the annotated type is used to annotate anything other than a class. Note also that this meta-annotation only causes annotations to be inherited from superclasses; annotations on implemented interfaces have no effect.
As soon as you annotate your implementing class, it works, which is also what you have described already. Sorry to have no better news, but this is how the Java compiler works.
Update: I forgot to mention that I developed a workaround using AspectJ (not Spring AOP) a while ago. If configured correctly, you can combine AspectJ and Spring AOP in one application.

how to inject a uiBinder with #Inject (instead of GWT.create())?

Firstly, is doing such thing a good practice ?
I tried what seems to be the right way for me but wasn't successful :
public class FormViewImpl extends CompositeView implements HasUiHandlers<C>, FormView {
public interface SettlementInstructionsSearchFormViewUiBinder extends UiBinder<Widget, SettlementInstructionsSearchFormViewImpl> {}
#Inject
static FormViewImpl uiBinder;
#Inject
static Provider<DateEditorWidget> dateEditorProvider;
#UiField(provided = true)
MyComponent<String> myComp;
#UiField
DateEditorWidget effectiveDateFrom;
// .. other fields
#Inject
public FormViewImpl () {
myComp = new MyComponent<String>("lol");
if (uiBinder == null)
uiBinder = GWT.create(SettlementInstructionsSearchFormViewUiBinder.class);
initWidget(uiBinder.createAndBindUi(this));
}
#UiFactory
DateEditorWidget createDateEditor() {
return dateEditorProvider.get();
}
}
What other things than a class with no arguments is required ? In my company's project the same kind of code works at some other place. Sorry from the high level of noob here...
If you guys had any pointers it would be nice.
Thanks
Two issues:
First, two of your #Inject fields are static - have you done anything to make static fields be injected? Static fields don't get set when Gin (or Guice) creates new instances, those have to be set once and done. As they are static, they will never be garbage collected - this may be okay with you, or it might be a problem, and you should change them to instance fields. If you want to keep them static, then you must invoke requestStaticInjection in your module to ask Gin to initialize them when the ginjector is created.
Next, if you do choose to remove static, the uiBinder field must still be null in that constructor, because the fields can't have been injected yet! How do you set a field on an object that you haven't yet created? That's what you are expecting Gin to be able to do. Instead, consider passing that as an argument into the #Inject decorated constructor. You don't even need to save it as a field, since the widget will only use it the one time.
To have a class generated by GIN (doesn't matter if it is a uiBinder or not) it is not necessary for it to have a default constructor (i.e. the one without parameters). The class you want to inject must have the constructor annotated with #Inject:
#Inject
public InjectMeClass(Object a, Object b)
The other class which is injected, suppose it is a UiBinder, must have the injected fields annotated with #UiField(provided=true):
public class Injected extends Composite {
private static InjectedUiBinder uiBinder = GWT
.create(InjectedUiBinder.class);
interface InjectedUiBinder extends UiBinder<Widget, Injected> {
}
#UiField(provided=true)
InjectMeClass imc;
public Injected(final InjectMeClass imc) {
this.imc=imc;
initWidget(uiBinder.createAndBindUi(this));
}
So, back to your case:
#UiField(provided = true)
MyComponent<String> myComp;
#Inject
public FormViewImpl (MyComponent<String> myComp) {
this.myComp = myComp;
and for example:
public class MyComponent<T> extends Composite {
private T value;
#Inject
public MyComponent(T t) {
this.value = t;
...
}
...
}
In the GIN module you can have a provider:
#Provides
#Singleton
public MyComponent<String> createMyComponent() {
return new MyComponent<String>("lol");
}

How do I request a subset of XMLElements using MOXy?

I have a RESTful service that needs to return only a few of the XmlElements if "selectors" are submitted with the request. The URL will take the form of:
/merchants/{merchantId}/profile?selectors=<field1|field2|....|fieldN>
The selectors are optional, and so far I have implemented the service for the full set of elements to be returned for {merchantId} without selectors specified. Now I'm trying to figure out how to add in this added functionality. I'm sure this is covered in documentation but I can't find where. Any RTFM pointers would be appreciated. Thanks.
EclipseLink JAXB (MOXy) does not currently offer a mechanism to selectively indicate which fields/properties are included on a per marshal operation. This sounds like an interesting use case. I would appreciate if you could enter this as an enhancement request using the following link:
https://bugs.eclipse.org/bugs/enter_bug.cgi?product=EclipseLink
Below is an example of how you could use a stateful XmlAdapter to implement this use case by exploiting the fact that a JAXB (JSR-222) will not marshal an element when the value is null (see: http://blog.bdoughan.com/2012/04/binding-to-json-xml-handling-null.html).
FieldAdapter
Since we are going to leverage stateful XmlAdapters we're going to need one per field. Since all our XmlAdapters will perform the same logic we can create a super class that the others can extend from.
package forum13094195;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class FieldAdapter<T> extends XmlAdapter<T, T> {
private boolean include;
public FieldAdapter() {
this.include = true;
}
public FieldAdapter(boolean include) {
this.include = include;
}
#Override
public T marshal(T value) throws Exception {
if(include) {
return value;
}
return null;
}
#Override
public T unmarshal(T value) throws Exception {
return value;
}
}
Field1Adapter
package forum13094195;
public class Field1Adapter extends FieldAdapter<String> {
public Field1Adapter() {}
public Field1Adapter(boolean include) {
super(include);
}
}
Field2Adapter
package forum13094195;
public class Field2Adapter extends FieldAdapter<Integer>{
public Field2Adapter() {}
public Field2Adapter(boolean include) {
super(include);
}
}
Field3Adapter
package forum13094195;
public class Field3Adapter extends FieldAdapter<String> {
public Field3Adapter() {}
public Field3Adapter(boolean include) {
super(include);
}
}
Merchant
The #XmlJavaTypeAdapter annotation is used to specify an XmlAdapter on a field/property.
package forum13094195;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Merchant {
#XmlJavaTypeAdapter(Field1Adapter.class)
String field1;
#XmlJavaTypeAdapter(Field2Adapter.class)
int field2;
#XmlJavaTypeAdapter(Field3Adapter.class)
String field3;
}
Demo
The demo code below demonstrates how to set a stateful XmlAdapter on the Marshaller.
package forum13094195;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Merchant.class);
Merchant merchant = new Merchant();
merchant.field1 = "A";
merchant.field2 = 2;
merchant.field3 = "C";
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(merchant, System.out);
marshaller.setAdapter(new Field1Adapter(false));
marshaller.setAdapter(new Field2Adapter(false));
marshaller.setAdapter(new Field3Adapter(true));
marshaller.marshal(merchant, System.out);
}
}
Output
Below is the output from running the demo code. By default the entire object is marshalled out. The second document marshalled does not contain the fields we excluded.
<?xml version="1.0" encoding="UTF-8"?>
<merchant>
<field1>A</field1>
<field2>2</field2>
<field3>C</field3>
</merchant>
<?xml version="1.0" encoding="UTF-8"?>
<merchant>
<field3>C</field3>
</merchant>
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
In EclipseLink 2.5.0 we released a new feature called Object Graphs that enables you to marshal/unmarshal a subset of mapped fields/properties.
// Create the Object Graph
ObjectGraph subset = JAXBHelper.getJAXBContext(jc).createObjectGraph(Merchant.class);
subset.addAttributeNodes("field1", "field1", "fieldN");
// Output XML - Based on Object Graph
marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, subset);
marshaller.marshal(customer, System.out);
For More Information
http://blog.bdoughan.com/2013/03/moxys-object-graphs-partial-models-on.html

Custom type converter for Mojo configuration?

I need to use custom type, e.g., LunarDate, in my Mojo object:
class MyMojo extends AbstractMojo {
/** #parameter */
LunarDate lunarDate;
}
And I want to configure the parameter in <configuration> section in pom.xml.
<configuration>
<lunarDate>丁丑年二月初四</lunarDate>
</configuration>
(The type LunarDate is just an example to illustrate the question)
I've already had the type converters, but how to enable them?
DefaultBeanConfigurator is responsible for using DefaultConverterLookup, and it instantiates it directly without using the Plexus Container.
You could I suppose copy and modify it in a build extension, but registering your copy via #Component(role=BeanConfigurator.class) will likely have no effect; I have tried replacing standard Maven components in the past from build extensions and been told on maven-dev that it is not possible.
You could look up the default BeanConfigurator and use reflection to get its ConverterLookup converterLookup field, then call registerConverter with your custom convertor, but this would be fragile.
Probably best is to just give up, declare your Mojo parameter to be of type String, and do the conversion explicitly in execute.
I was able to solve this by defining a ConfigurationConverter (my target
type is a AnyLicenseInfo):
#NoArgsConstructor #ToString
public class LicenseConverter extends AbstractBasicConverter {
private static final Class<?> TYPE = AnyLicenseInfo.class;
#Override
public boolean canConvert(Class<?> type) { return type.equals(TYPE); }
#Override
public Object fromString(String string) throws ComponentConfigurationException {
Object object = null;
try {
object =
TYPE.cast(LicenseInfoFactory.parseSPDXLicenseString(string));
} catch (Exception exception) {
String message =
"Unable to convert '" + string + "' to " + TYPE.getName();
throw new ComponentConfigurationException(message, exception);
}
return object;
}
}
Registering it with a custom ComponentConfigurator:
#Named("license-mojo-component-configurator")
#NoArgsConstructor #ToString #Slf4j
public class LicenseMojoComponentConfigurator extends BasicComponentConfigurator {
#PostConstruct
public void init() {
converterLookup.registerConverter(new LicenseConverter());
}
#PreDestroy
public void destroy() { }
}
And then specifying the configurator in the #Mogo annotation:
#Mojo(name = "generate-license-resources",
configurator = "license-mojo-component-configurator",
requiresDependencyResolution = TEST,
defaultPhase = GENERATE_RESOURCES, requiresProject = true)
#NoArgsConstructor #ToString #Slf4j
public class GenerateLicenseResourcesMojo extends AbstractLicenseMojo {
For newer Maven (tested with Maven 3.3.1) you can now subclass BasicComponentConfigurator to access the DefaultConverterLookup as a member variable:
#Component(role = ComponentConfigurator.class, hint = "basic")
public class ExtendedComponentRegistrator
extends BasicComponentConfigurator
implements Initializable {
#Override
public void initialize() throws InitializationException {
converterLookup.registerConverter(new MyCustomConverter());
}
}
Then in the pom.xml enable the generation of plexus meta data:
<plugin>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-component-metadata</artifactId>
<executions>
<execution>
<goals>
<goal>generate-metadata</goal>
</goals>
</execution>
</executions>
</plugin>

MEF Exporting and Importing abstract types

I have a factory class which imports a list of IOperation types. I get the following error when I try and resolve the factory class:
Resulting in:
Cannot activate part
'Message36Operation'. Element:
Message36Operation -->
Message36Operation --> DirectoryCatalog
(Path=".\")
Resulting in:
Cannot get export 'Message36Operation
(ContractName="IOperation")' from part
'Message36Operation'. Element:
Message36Operation
(ContractName="IOperation") -->
Message36Operation --> DirectoryCatalog
(Path=".\")
Resulting in:
Cannot set import
'OperationsFactory.Operations
(ContractName="IOperation")' on part
'OperationsFactory'. Element:
OperationsFactory.Operations
(ContractName="IOperation") -->
OperationsFactory --> AssemblyCatalog
(Assembly="RmiToODKMessanger, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null")
Here's what I have:
[Export(typeof(OperationsFactory))]
public class OperationsFactory
{
[ImportMany(typeof(IOperation))]
private IEnumerable<IOperation> Operations { get; set; }
}
public interface IOperation
{
}
public abstract class BaseRmiOperation : IOperation
{
}
[Export(typeof(IOperation))]
public class Message36Operation : BaseRmiOperation, IOperation
{
}
The exception is thrown will I try and resolve an instance of the factory.
I can get this to work if I remove the abstract class.
Any ideas,
Thanks,
Ken
** Update:
Below is the BaseRmiOperation class. I'm instantiating a few classes in the cstor and that's it.
I forgot to mention the structure of the app previously.
CG.App: contains OperationsFactory and bootstrapper class for MEF.
CG.Plugins : Contains various IOperation implementations such as Message36Operation and the BaseRmiOperation abstract class
CG.Common : Contains IOperation interface. This assembly is referenced by both CG.App and CG.Plugins
The CG.App.Bootstrapper class loads the plugins from bin/plugins.
public abstract class BaseRmiOperation : IOperation
{
protected SettingsManager _settingsManager;
protected RmiMessenger _messenager;
protected ILogger _logger;
protected TagManager _tagManager;
protected Environments _rmiEnvironment;
protected string _msgSource;
protected string _emp_id;
public BaseRmiOperation()
{
this._settingsManager = new SettingsManager();
this._messenager = new RmiMessenger(null, null);
this._tagManager = new TagManager(); // pass ILogger
//this._logger = logger;
// pulls the rmi_env and a few other settings from
// winCC.
PopulateRmiSettings();
}
public abstract ExitCodes Execute(object[] data);
public abstract string Description { get; }
public abstract string Alias { get; }
Sorted the problem. Silly mistake. The TagManager assembly was not present in the /bin folder and was causing the BaseRmiOperation cstor to crash. A breakpoint at the start of the cstor was never being called, it always crashed on the line to resolve the OperationFactory. Figured it out by going back to basics and adding functionality one line at a time. Thanks.