How to import classes as interfaces using Import / ImportMany in Prism? - prism

I'm trying to import classes of a certain interface type. I already looked for help (e.g. here), but I can't seem to get it working.
First, I tried the following:
public interface ISomeInterface
{
...
}
[Export(typeof(ISomeInterface))]
public class SomeImplementation: ISomeInterface
{
...
}
[ImportingConstructor]
public ScannerMainViewModel([ImportMany(typeof(ISomeInterface))] IEnumerable<ISomeInterface> someImplementations)
{
...
}
But someImplementations is null.
Then I removed the ImportMany from the constructor and used it on the field
[ImportMany(typeof(ISomeInterface))]
private IEnumerable<ISomeInterface> someImplementations;
with the same result.
I then removed the ImportMany completely and only imported my one class this way:
[ImportingConstructor]
public ScannerMainViewModel(ISomeInterface someImplementation)
{
...
}
This lead to the folling error:
An exception has occurred while trying to add a view to region 'MainRegion'.
- The most likely causing exception was was: 'System.InvalidOperationException: No public constructor is available for type Common.Interfaces.IAccountScanner. ---> Unity.Exceptions.InvalidRegistrationException: Eine Ausnahme vom Typ "Unity.Exceptions.InvalidRegistrationException" wurde ausgelöst.
What am I doing wrong? I also tried to use names for contracts, but that didn't work too.

Related

Customize pointcut expression for 'declare #method'

Use case
I'd like to add programmatically an externally provided annotation named: #Trace
to all public methods in the spring-boot project
that are in a class annotated with #Controller
only within a particular package (com.example.apectitddemo.controller)
only if the method doesn't have a different custom annotation already applied, f.e. #Disable
Thanks to the above criteria, each newly added method to the project that meets them all will be #Trace annotated dynamically without any additional developer action, which is the main goal here.
My approach
I used Aspectj's ITD (inter type declaration) for this but it fulfills only 1st requirement and have no idea how to customize it for 2nd, 3rd and 4th.
Tried several ways commented out in the below code snipped.
TracingAspect.aj:
package com.example.apectitddemo.aspect;
public aspect TracingAspect {
declare #method : public * *(..) : #Trace;
//[INFO] 'public void com.example.apectitddemo.controller.ControllerPing.ping()' (ControllerPing.java) is annotated with #Trace method annotation from 'com.example.apectitddemo.aspect.TracingAspect' (TracingAspect.aj)
// declare #method : public * ((#Controller *)).*(..) : #Trace;
// declare #method : public * ((#Controller *)).*(..) && !#Disabled : #Trace;
// declare #method : public com.example.apectitddemo.controller.* :#Trace;
// declare #method : public * com.example.apectitddemo.controller+ : #Trace;
// declare #method : public * *(com.example.apectitddemo.controller.*) : #Trace;
// declare #method : public * controller..* : #Trace;
// declare #method : public * *(..) : #Trace;
}
BTW is it possible to use pure java here (TracingAspect.java) and not as .aj file?
ControllerPing.java (sample method which should be annotated by an aspect)
package com.example.apectitddemo.controller
#Controller
public class ControllerPing {
//#Trace annotation should be added here by ITD
public void ping() {
log.info("ok");
}
#Disable
public void pingDisabled() {
log.info("ok");
}
}
Misc
I was searching the internet but haven't found much documentation and even couldn't encounter any other code samples except below. The above solution is based on this finding:
how to write an aspectj itd to add an annotation to a method?
Other pages found, related:
https://www.eclipse.org/aspectj/doc/released/adk15notebook/ataspectj-itds.html
http://kto.web.elte.hu/hu/oktatas/aop_en.pdf
samples are empty :/ https://www.eclipse.org/aspectj/doc/released/examples/
Maybe there is another better way to complete the requirements?
This is a native AspectJ example. You can run it completely without Spring or from within a Spring application - up to you:
Annotations:
package de.scrum_master.stackoverflow.q73270343;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
#Retention(RUNTIME)
#Target({ METHOD })
public #interface Trace {}
package de.scrum_master.stackoverflow.q73270343;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
#Retention(RUNTIME)
#Target({ METHOD })
public #interface Disable {}
Non-controller class (negative test):
package de.scrum_master.stackoverflow.q73270343;
public class NoControllerPing {
// #Trace annotation should NOT be added here by ITD
public void ping() {
System.out.println("No controller ping");
}
#Disable
public void pingDisabled() {
System.out.println("No controller pingDisabled");
}
}
Controller class and driver application:
package de.scrum_master.stackoverflow.q73270343;
import org.springframework.stereotype.Controller;
#Controller
public class ControllerPing {
// #Trace annotation should be added here by ITD
public void ping() {
System.out.println("Controller ping");
}
#Disable
public void pingDisabled() {
System.out.println("Controller pingDisabled");
}
public static void main(String[] args) {
new ControllerPing().ping();
new ControllerPing().pingDisabled();
new NoControllerPing().ping();
new NoControllerPing().pingDisabled();
}
}
Native syntax AspectJ aspect:
package de.scrum_master.stackoverflow.q73270343;
public aspect TracingAspect {
declare #method : !#Disable public !static * (#org.springframework.stereotype.Controller *..*).*(..) : #Trace;
before() : #annotation(Trace) && execution(* *(..)) {
System.out.println(thisJoinPoint);
}
}
Console log:
execution(void de.scrum_master.stackoverflow.q73270343.ControllerPing.ping())
Controller ping
Controller pingDisabled
No controller ping
No controller pingDisabled
See AspectJ manual.
BTW is it possible to use pure java here (TracingAspect.java) and not as .aj file?
No, it is not. Quote from the AspectJ manual:
Inter-type declarations are challenging to support using an annotation style. For code style aspects compiled with the ajc compiler, the entire type system can be made aware of inter-type declarations (new supertypes, new methods, new fields) and the completeness and correctness of it can be guaranteed. Achieving this with an annotation style is hard because the source code may simply be compiled with javac where the type system cannot be influenced and what is compiled must be 'pure java'.
You only have #DeclareParents, #DeclareMixin, #DeclarePrecedence, #DeclareWarning, #DeclareError at your disposal. See also the AspectJ 5 quick reference, page 4.

Creating a controller method that saves an object within an object

I am trying to create a controller for a microservice in which a vehicle object is created, however within this vehicle object, we must save a registration object first. I am able to do the vehicle controller, but am unsure how to have the registration object saved within the vehicle object. Here is what the JSON objects should look like in the end.
JSON input:
{
"make":"Chevrolet",
"Model":"Silverado 1500",
"modelYear":2009,
"registration": {
"licensePlate":"TOWME2",
"licensedTo":"Ford Towers"
}
}
JSON output:
{
"id":[auto-generated],
"make":"Chevrolet",
"model":"Silverado 1500",
"modelYear":2009,
"registration": {
"id":[auto-generated],
"licensePlate":"TOWME2",
"licensedTo":"Ford Towers"
}
}
I too faced this issue and it's because spring-boot-starter-data-rest excludes ID fields.
To customize how it behaves, you can extend RepositoryRestConfigurerAdapter to expose IDs for specific classes.
import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;
#Configuration
public class RepositoryConfig extends RepositoryRestConfigurerAdapter {
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(Vehicle.class);
}
}

Use method names from one of my classes usign reflection for creating a maven archetype

I am a complete novice creating maven archetypes, I have been reading a lot of posts before I decided to ask this question. I want to create a template to build new projects following an structure defined by an interface (created by me):
package com.jh.interfaces;
public interface VideoPlayerInterface {
void play();
void pause();
void rewind();
void stop();
void fastFordward();
}
I would like to create a class which overrides whose methods, something like this:
package com.jh.impl;
public class VideoPlayerCustom implements VideoPlayerInterface {
public void play(){}
public void pause(){}
public void rewind(){}
public void stop(){}
public void fastFordward(){}
}
In order to do that, I found topics in SO that used reflection to do similar stuff with Java classes, but I wasn't able to get results using my interface even with a simple operation to start:
public class ${library-name}Client
{
#set( $year = $package.getClass().forName("java.util.Date").newInstance().getYear() + 1900 )
#set( $name = $package.getClass().forName("com.jh.interfaces.VideoPlayerInterface").getSimpleName() )
public void ${name}${year}(){}
}
${year} contains the current year (it works fine), but ${name} fails when creating project from maven archetype:
generate (default-cli) on project standalone-pom: org.apache.maven.archetype.exception.ArchetypeGenerationFailure: Error merging velocity templates: Invocation of method 'forName' in class java.lang.Class threw exception java.lang.ClassNotFoundException: com.jh.interfaces.VideoPlayerInterface at archetype-resources/src/main/java/__library-name__Client.java[line 10, column 39]
Has anyone gone through a similar issue?
Thanks
An easy approach :
Use the reflation related stuff in Java code, get the declared methods and add methods array/list to the velocity context.
String sourceClassName = "com.jh.interfaces.VideoPlayerInterface";
try {
Class sourceClass = Class.forName(sourceClassName);
Method[] methods = (Method[]) ArrayUtils.addAll(methods, sourceClass.getDeclaredMethods());
context.put("methods", methods);
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
}
Then you can write your template something like this :
package com.jh.impl;
public class VideoPlayerCustom implements VideoPlayerInterface {
#foreach ($method in $methods)
public void $method.getName()(){}
#end
}

JSF ManagedProperty not working for class

Sorry for my English. I want to set #ManagedProperty for class TaskBO, but it is not works. TaskMB class:
#ManagedBean(name="taskMB")
#RequestScoped
public class TaskMB implements Serializable {
#ManagedProperty(value="#{TaskBO}")
public TaskBO taskBO;
public TaskBO getTaskBO() {
return this.taskBO;
}
public void setTaskBO(TaskBO taskBO){
this.taskBO = taskBO;
}
//...
}
It prints the error:
javax.servlet.ServletException: Unable to set property taskBO for managed bean taskMB
javax.el.ELException: java.lang.IllegalArgumentException: Cannot convert com.otv.model.bo.TaskBO#6c80b8 of type class $Proxy135 to class com.otv.model.bo.TaskBO
But if I add interface ITaskBO, that it is works:
#ManagedProperty(value="#{TaskBO}")
public ITaskBO taskBO;
public ITaskBO getTaskBO() {
return this.taskBO;
}
public void setTaskBO(ITaskBO taskBO){
this.taskBO = taskBO;
}
Why not work #ManagedProperty with the class TaskBO?
Is best pratice wire interface instead of concrete class to prevent the problem you encountered.
Cannot convert com.otv.model.bo.TaskBO#6c80b8 of type class $Proxy135
to class com.otv.model.bo.TaskBO
Often Spring's managed object are proxied and a java proxy can be casted ONLY to interface and not to concrete class; the error above is generated because:
TaskBO object is managed by Spring and proxied to an object of type $Proxy135 (the real type of your object now is not really concrete class TaskBO but a proxy you can cast to ITaskBO, the $Proxy135)
you are trying to do some like public TaskBO taskBO = (TaskBO)$Proxy135; but cast a proxy to concrete class is impossible
The right way is to write public ITaskBO taskBO = (ITaskBO)$Proxy135; and this works because a proxy can be cast only to interface
Avoid - as much as possible - use of concrete class in favor of interface.
In addiction you can look here if you are mixing configuration how described in linked question.

How to write annotation processor to raise a warning message if a java source is calling an annotated method

Here is my requirement in Java 6: I am using Eclipse JUNO.
Annotate a method with a custom annotation.
During compilation, raise warning message if a method is calling the
annotated method.
I am looking for something like #Deprecated annotation.
This is what I have done:
Wrote a custom annotation.
Wrote an annotation processor to read and process the methods with
the annotation.
Created a jar and added it in annotation processor path. My sample code (see below) raises the warning message in the annotated method. But it is not my requirement.
What I couldn’t do:
I could not get the calling methods. I want to raise the warning
message in those calling methods.
My sample code:
Custom annotation:
package tool.apichecks;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.SOURCE)
#Target({ ElementType.METHOD })
public #interface HighCostMethod {
String altMethod();
}
Annotation Processor:
package tool.apichecks;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
#SupportedAnnotationTypes({ "tool.apichecks.HighCostMethod" })
public class MethodProcessor extends AbstractProcessor {
private enum MethodType {
HIGH_COST(HighCostMethod.class.getName());
private String name;
private MethodType(String name) {
this.name = name;
}
private static MethodType getMethodType(String name) {
MethodType methodType = null;
for (MethodType methodType2 : MethodType.values()) {
if (methodType2.name.equals(name)) {
methodType = methodType2;
break;
}
}
return methodType;
}
}
private ProcessingEnvironment processingEnvironment;
#Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
this.processingEnvironment = processingEnvironment;
}
#Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnvironment) {
if (!roundEnvironment.processingOver()) {
for (TypeElement annotation : annotations) {
final Set<? extends Element> elements = roundEnvironment
.getElementsAnnotatedWith(annotation);
MethodType methodType = MethodType.getMethodType(annotation
.toString());
for (Element element : elements) {
switch (methodType) {
case HIGH_COST: {
processHighCostMethod(element);
break;
}
}
}
}
}
return true;
}
protected void processHighCostMethod(Element element) {
HighCostMethod highCostMethod = element
.getAnnotation(HighCostMethod.class);
/* TODO This warns the annotated method itself. I don't want this. I want to warn the methods that calls this method */
processingEnvironment
.getMessager()
.printMessage(
Kind.WARNING,
String.format(
"Do not use high cost method %s. Instead use %s method.",
element, highCostMethod.altMethod()), element);
}
}
Using an AnnotationProcessor will only work on the files containing the annotations or overriding methods, but not calling methods. Maybe there's a way around this, but then you will probably be limited by projects, because the processor only looks at one project at a time.
I guess you need to write an Eclipse plugin with a builder, that analyses code in all files and checks called methods for annotations.
That a lot more work than an annotation processor, but you also have more options. E.g. you could implement a quick fix for the error markers.

Resources