Howto inject Plexus component into Mojo - maven-3

Is it possible to inject a Plexus component into a Mojo.
Here's what I tried but myComponent is always null.
My Component:
import org.codehaus.plexus.component.annotations.Component;
#Component(role = MyComponent.class, hint = "mine")
public class MyComponent {
}
My Mojo:
import org.codehaus.plexus.component.annotations.Requirement;
import org.apache.maven.plugins.annotations.Component;
public class MyMojo extends AbstractMojo {
#Requirement(role = MyComponent.class, hint = "mine", optional = false)
protected MyComponent myComponent;
#Component
protected MavenProject project;
}

You Java part is correct, but you need to add some sources processing to build of your Maven plugin. This can be achieved by adding the following to your build in pom.xml:
<plugin>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-component-metadata</artifactId>
<version>2.0.0</version>
<executions>
<execution>
<id>process-classes</id>
<goals>
<goal>generate-metadata</goal>
</goals>
</execution>
</executions>
</plugin>

Related

Quarkus UnsatisfiedResolutionException for Mapstruct

I am trying to use Mapstruct in my Quarkus project, but when i run the app with /.mvnw compile quarkus:dev
i got the following exception:
javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type
org.acme.dto.mapper.BookMapper and qualifiers [#Default]
(I have checked the generated classes in target/generated-sources, and they get #ApplicationScoped)
Details:
Mapstruct dependencies are added to the pom.xml as:
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
<scope>provided</scope>
</dependency>
Than i have several mappers like:
#Mapper(componentModel = "cdi", uses = { BookDetailsMapper.class, AuthorMapper.class })
public interface BookMapper {
BookDto toDto(Book book);
Book toEntity(BookDto bookDto);
}
#Mapper(componentModel = "cdi")
public interface AuthorMapper {
AuthorDto toDto(Author author);
Author toEntity(AuthorDto author);
}
#Mapper(componentModel = "cdi")
public interface BookDetailsMapper {
BookDetailsDto toDto(BookDetails bookDetails);
BookDetails toEntity(BookDetailsDto bookDetailsDto);
}
And the BookMapper bean is injected in:
#ApplicationScoped
public class BookService {
private final BookMapper bookMapper;
#Inject
public BookService(BookMapper bookMapper) {
this.bookMapper = bookMapper;
}
...
The problem was that generated-sources of mapstruct was not compiled to class files.
I had to add the mapstruct-processor dependency as follows:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId>
<version>${quarkus.platform.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>

Neo4j Procedure throwing error

I'm just starting to learn how to write procedures. My simple proof of concept still isn't passing muster when Neo4j starts up. Here is the code:
import java.util.ArrayList;
import java.util.stream.Stream;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.logging.Log;
import org.neo4j.procedure.Context;
import org.neo4j.procedure.Mode;
import org.neo4j.procedure.Procedure;
public class Procedures {
#Context
public GraphDatabaseService db;
#Context
public Log log;
#Procedure( name = "create_user", mode = Mode.WRITE )
public Stream<Create_user_response> create_user() {
ArrayList<Create_user_response> myList = new ArrayList<>();
Create_user_response res1 = new Create_user_response();
res1.out = 1;
myList.add(res1);
Stream<Create_user_response> myStream = myList.stream();
return myStream;
}
}
Here's my Create_user_response class:
public class Create_user_response {
public int out;
}
When Neo4j starts up it complains that my procedure needs to return a stream of records. I'm new to streams so I must be doing something wrong but just can't figure it out.
I appreciate any help. Thanks.
Turns out I had a bad dependency,
<dependency>
<groupId>org.neo4j.test</groupId>
<artifactId>neo4j-harness</artifactId>
<version>3.2.3</version>
<scope>test</scope>
</dependency>
wasn't working. I found it in a tutorial and its in Maven, but for some reason I must not have been doing something correctly with it.

UserTypeResolver must not be null

I have been attempting to test out an insert of a Cassandra UDT, and i keep running into the following error:
Exception in thread "main" java.lang.IllegalArgumentException: UserTypeResolver must not be null
After just trying to figure my own way through it, i attempted to exactly replicate the approach outlined in the following:
User Defined Type with spring-data-cassandra
However, i still get the same error.
I am able to insert to the target DB when i remove the UDT and just insert the simple types, so I know that I am connecting appropriately. My config is as follows:
#Configuration
#PropertySource(value = { "classpath:cassandra.properties" })
//#EnableCassandraRepositories(basePackages = { "org.spring.cassandra.example.repo" })
public class CassandraConfig {
private static final Logger LOG = LoggerFactory.getLogger(CassandraConfig.class);
#Autowired
private Environment env;
#Bean
public CassandraClusterFactoryBean cluster() {
CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean();
cluster.setContactPoints(env.getProperty("cassandra.contactpoints"));
cluster.setPort(Integer.parseInt(env.getProperty("cassandra.port")));
return cluster;
}
#Bean
public CassandraMappingContext mappingContext() {
BasicCassandraMappingContext mappingContext = new BasicCassandraMappingContext();
mappingContext.setUserTypeResolver(new SimpleUserTypeResolver(cluster().getObject(), "campaign_management"));
return mappingContext;
}
#Bean
public CassandraConverter converter() {
return new MappingCassandraConverter(mappingContext());
}
#Bean
public CassandraSessionFactoryBean session() throws Exception {
CassandraSessionFactoryBean session = new CassandraSessionFactoryBean();
session.setCluster(cluster().getObject());
session.setKeyspaceName(env.getProperty("cassandra.keyspace"));
session.setConverter(converter());
session.setSchemaAction(SchemaAction.NONE);
return session;
}
#Bean
public CassandraOperations cassandraTemplate() throws Exception {
return new CassandraTemplate(session().getObject());
}
}
My Address and Employee classes are exactly as shown in the SO question i reference above, and my Main is simply:
public class MainClass {
public static void main(String[] args) {
ApplicationContext service = new AnnotationConfigApplicationContext(CassandraConfig.class);
Employee employee = new Employee();
employee.setEmployee_id(UUID.randomUUID());
employee.setEmployee_name("Todd");
Address address = new Address();
address.setAddress_type("Home");
address.setId("ToddId");
employee.setAddress(address);
CassandraOperations operations = service.getBean("cassandraTemplate", CassandraOperations.class);
operations.insert(employee);
System.out.println("Done");
}
}
I am using:
datastax.cassandra.driver.version=3.1.3
spring.data.cassandra.version=1.5.1
spring.data.commons.version=1.13.1
spring.cql.version=1.5.1
The version referenced in the previous SO question is 1.5.0, though spring.io lists 1.5.1 as current, so I am using that, and no 1.5.0 is shown available.
Any help would be appreciated, as this is driving me somewhat nuts.
You typically get this error when you miss a UserTypeResolver under your cassandra Mapping, itself used by the cassandra Converter, itself used by the Spring Data Cassandra Template
For the details:
Assuming you have a basic Spring MVC Controller up and running elsewhere...
UserDefinedTypes in Cassandra being most interesting within SETs and MAPs, the example below is of such kind.
Example Spring Bean configuration with all defaults (Spring XML application context extract):
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cassandra="http://www.springframework.org/schema/data/cassandra"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/data/cassandra http://www.springframework.org/schema/data/cassandra/spring-cassandra.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
...
<!-- ===== CASSANDRA ===== -->
<!-- Loads the properties into the Spring Context and uses them to fill in placeholders in bean definitions below -->
<context:property-placeholder location="/WEB-INF/spring/cassandra.properties" />
<!-- REQUIRED: The Cassandra Cluster -->
<cassandra:cluster contact-points="${cassandra.contactpoints}"
port="${cassandra.port}" username="cassandra" password="cassandra"
auth-info-provider-ref="authProvider" />
<!-- REQUIRED: The Cassandra Session, built from the Cluster, and attaching to a keyspace -->
<cassandra:session keyspace-name="${cassandra.keyspace}" />
<!-- REQUIRED: The Default Cassandra Mapping Context used by CassandraConverter
DO include a userTypeResolver for UDT support -->
<cassandra:mapping entity-base-packages="fr.woobe.model">
<cassandra:user-type-resolver keyspace-name="${cassandra.keyspace}" />
</cassandra:mapping>
<!-- REQUIRED: The Default Cassandra Converter used by CassandraTemplate -->
<cassandra:converter />
<bean id="authProvider" class="com.datastax.driver.core.PlainTextAuthProvider">
<constructor-arg index="0" value="myCassandraUser" />
<constructor-arg index="1" value="somePassword" />
</bean>
<!-- REQUIRED: The Cassandra Template is the building block of all Spring Data Cassandra -->
<cassandra:template id="cassandraTemplate" />
...
and then in java, typically within your Spring MVC controller:
import org.springframework.data.cassandra.core.CassandraOperations;
...
// acquire DB template
CassandraOperations cOps = this.beanFactory.getBean("cassandraTemplate", CassandraOperations.class);
// for instance: load everything
List<MyData> rows = cOps.select("SELECT * FROM mydatatable", MyData.class);
// assuming an entry with index i exists...
Set<Pair> mySetOfPairs = rows.get(i).pairSet;
if (mySetOfPairs!=null)
for (Pair p : mySetOfPairs) {
... handle p.first and p.second ...
...
with this kind of entity mappings:
package example.model;
import java.util.Set;
import org.springframework.data.cassandra.core.mapping.CassandraType;
import org.springframework.data.cassandra.core.mapping.PrimaryKey;
import org.springframework.data.cassandra.core.mapping.Table;
import com.datastax.driver.core.DataType.Name;
#Table public class MyData {
#PrimaryKey
public String myKey;
// some other basic fields...
public String moreStuff;
// a SET of user defined 'pair type'
#CassandraType(type = Name.SET, userTypeName = "pairType")
public Set<Pair> pairSet;
// your constructors and other methods here...
}
and a user defined entity like:
package example.model;
import org.springframework.data.cassandra.core.mapping.UserDefinedType;
#UserDefinedType("pairType")
public class Pair {
public String first;
public String second;
public Pair() {
}
public Pair(String f, String s) {
this.first= f;
this.second= s;
}
}
all based on a Cassandra table created as:
CREATE TYPE pairType (first text, second text);
CREATE TABLE MyData (
myKey text,
moreStuff text,
pairSet set<frozen<pairType>>,
PRIMARY KEY (myKey)
) ;
INSERT INTO MyData (myKey, moreStuff, pairSet)
VALUES ('hello', 'world', {
{ first:'one', second:'two' },
{ first:'out', second:'there' } }
) ;
In term of Maven artifacts or libraries, spring-webmvc is indeed required if you run within a Web MVC Spring Controller, and then spring-context-support, and spring-data-cassandra. The DataStax cassandra driver comes along as a dependency.

"Destination is mandatory" when mixing annotations and deployment descritors

i'm trying to define a message driven bean with annotations and deployment descriptors on wildfly 8.2.0-Final . I want to declare the static parts of the configuration with annotations, variable parts with xml deployment descriptors. When deploying the following mdb, i'm getting an exception.
Here's the content of the .failed-File:
{"JBAS014671: Failed services" => {"jboss.deployment.unit.\"MdbWithAnnotationsAndDescritors.jar\".component.NewMessageBean.START" => "org.jboss.msc.service.StartException in service jboss.deployment.unit.\"MdbWithAnnotationsAndDescritors.jar\".component.NewMessageBean.START: java.lang.RuntimeException: javax.resource.spi.InvalidPropertyException: Destination is mandatory
Caused by: java.lang.RuntimeException: javax.resource.spi.InvalidPropertyException: Destination is mandatory
Caused by: javax.resource.spi.InvalidPropertyException: Destination is mandatory"}}
The mdb is
package test;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSDestinationDefinition;
import javax.jms.Message;
import javax.jms.MessageListener;
#JMSDestinationDefinition(name = "testQueue", interfaceName = "javax.jms.Queue", resourceAdapter = "jmsra", destinationName = "testQueue")
#MessageDriven(activationConfig = {
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
public class NewMessageBean implements MessageListener {
public NewMessageBean() {
}
#Override
public void onMessage(Message message) {
}
}
and the jboss.xml deployment descriptor:
<jboss xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss_5_0.xsd" version="3.0">
<security-domain>tutorial-default</security-domain>
<enterprise-beans>
<message-driven>
<ejb-name>testQueue</ejb-name>
<destination-jndi-name>testQueue</destination-jndi-name>
</message-driven>
</enterprise-beans>
</jboss>
the ejb-jar.xml is empty:
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns="http://xmlns.jcp.org/xml/ns/javaee"
version="3.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/ejb-jar_3_2.xsd">
</ejb-jar>
Got it, i added the destination ActivationConfigProperty to the mdb class to get rid of the exception:
package test;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSDestinationDefinition;
import javax.jms.Message;
import javax.jms.MessageListener;
/**
*
* #author rainer
*/
#MessageDriven(activationConfig = {
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "destination", propertyValue = "willBeOverwrittenInDeploymentDescriptor")
})
public class NewMessageBean implements MessageListener {
public NewMessageBean() {
}
#Override
public void onMessage(Message message) {
}
}
I removed the JMSDestinationDefinition because its not needed, i created the queue with the management console.
To overwrite the destination jndi name, i created the following ejb-jar.xml
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd">
<enterprise-beans>
<message-driven>
<ejb-name>NewMessageBean</ejb-name>
<ejb-class>test.NewMessageBean</ejb-class>
<activation-config>
<activation-config-property>
<activation-config-property-name>destination</activation-config-property-name>
<activation-config-property-value>/jms/testClientQueue</activation-config-property-value>
</activation-config-property>
</activation-config>
</message-driven>
</enterprise-beans>
</ejb-jar>
Now the mdb gets deployed and listens to the queue jms/testClientQueue
You need to define in ejb-jar.xml not jboss.xml
You might however prefer to use annotation substitution where the values are pulled from system properties or in jboss.properties in newer versions of wildfly or EAP 6.4

#PreAuthorize: reference property in implementing class

I have service interface
public interface CompoundService<T extends Compound> {
T getById(final Long id);
//...
}
and abstract implementation
public abstract class CompoundServiceImpl<T extends Compound>
implements CompoundService<T> {
//...
private Class<T> compoundClass;
//...
}
Every implementation of Compound requires it's own service interface which extends CompoundService and it's own service class which extends CompoundServiceImpl.
I would now like to add basic security uisng annotations to my methods in CompoundService. As far as I understood I must add them in the interface not the actual implementation. Since a user can have different roles for different implementations of Compound, i must take this into account. Meaning in #PreAuthorize I would like to get the name of the Compound implementation, eg. compoundClass.getSimpleName(). So that I get something like:
public interface CompoundService<T extends Compound> {
#PreAuthorize("hasRole('read_' + #root.this.compoundClass.getSimpleName())")
T getById(final Long id);
//...
}
This is basically what is mentioned here:
https://jira.springsource.org/browse/SEC-1640
however there is no example and I did not really get the solution. So should i use this? or as above #root.this?
My second question is, since this is in an interface which will be implemented by a proxy (from spring) will the experession this.compoundClass actually evaluate properly?
And last but not least how can I actually test this?*
*
I'm not actually creating a finished application but something configurable, like a framework for s specific type of database search. Meaning most authorization and authentication stuff has to come from the implementer.
Unit Testing
see http://www.lancegleason.com/blog/2009/12/07/unit-testing-spring-security-with-annotations
Since that is an old tutorial you might need to change the referenced schema versions. But more importantly the SecurityContext.xml configuration shown there does not work with Spring Security 3. See Spring Security - multiple authentication-providers for a proper configuration.
I did not require the mentioned dependencies:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core-tiger</artifactId>
</dependency>
it worked without them (however did not create an abstract test class)
root.this
This is in fact correct approach
The problem is that you can't use getSimpleName() of a class parameter. For an in-depth discussion see http://forum.springsource.org/showthread.php?98570-Getting-Payload-Classname-in-Header-Enricher-via-SpEL
The workarounds shown there did not help me much. So I came up with this very simple solution:
Just add the string property String compoundClassSimpleName to CompoundServiceImpl and set it in the constructor (which is called by subclasses):
Public abstract class CompoundServiceImpl<T extends Compound>
implements CompoundService<T> {
private String compoundClassSimpleName;
//...
public ChemicalCompoundServiceImpl(Class<T> compoundClass) {
this.compoundClass = compoundClass;
this.compoundClassSimpleName = compoundClass.getSimpleName();
}
//...
public String getCompoundClassSimpleName(){
return compoundClassSimpleName;
}
}
and her a Service implementing above abstract service:
public class TestCompoundServiceImpl extends CompoundServiceImpl<TestCompound>
implements TestCompoundService {
//...
public TestCompoundServiceImpl() {
super(TestCompound.class);
}
//...
}
And final the #PreAuthorize annotation usage:
public interface CompoundService<T extends Compound> {
#PreAuthorize("hasRole('read_' + #root.this.getCompoundClassSimpleName())")
public T getById(final Long id);
}
For above example the expression will evaluate to a role named "read_TestCompound".
Done!
As often the solution is very simple but getting there is a PITA...
EDIT:
for completeness the test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {
"classpath:ApplicationContext.xml",
"classpath:SecurityContext.xml"
})
public class CompoundServiceSecurityTest {
#Autowired
#Qualifier("testCompoundService")
private TestCompoundService testCompoundService;
public CompoundServiceSecurityTest() {
}
#Before
public void setUp() {
SecurityContextHolder.getContext().setAuthentication(
new UsernamePasswordAuthenticationToken("user_test", "pass1"));
}
#Test
public void testGetById() {
System.out.println("getById");
Long id = 1000L;
TestCompound expResult = new TestCompound(id, "Test Compound");
TestCompound result = testCompoundService.getById(id);
assertEquals(expResult, result);
}
}

Resources