I want to be able to store a Set of fully qualified Class names as a property of a Node. Given this Node:
#NodeEntity
public TestNode {
Set<Class<?>> classSet;
//getters and setters here
}
And the following custom converters:
public class ClassToStringConverter implements Converter<Class<?>, String> {
#Override
public String convert(final Class<?> source) {
return source.getName();
}
}
public class StringToClassConverter implements Converter<String, Class<?>> {
#Override
public String convert(final String source) {
Class<?> returnVal = null;
try {
returnVal = Class.forName(source);
} catch (ClassNotFoundException e) { }
return returnVal;
}
}
I register the converters with Spring context as such:
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="my.package.ClassToStringConverter"/>
<bean class="my.package.StringToClassConverter "/>
</set>
</property>
</bean>
Then using my repository, I can properly save and retrieve the Node, and it stores the fully qualified class name as expected using my custom converters. However, I would like to be able to query by a Class name as such in my repository:
#Query("MATCH (m:TestNode) where {0} in m.classSet return m;")
public findByClassInClassSet(Class<?> clazz);
However, this seems to convert the Class using Class.toString() instead of using my Converter. So it is searching for the String "class my.package.TestNode" instead of what the Converter correctly stored as "my.package.TestNode".
Am I missing something here or doing something wrong? How can I benefit from these converters if I can't query using the Class type?
NOTE: Please excuse any typos - this code is on a disconnected network so I couldn't copy paste. If there are any typos, I assure you that is not the problem on my actual code.
Should be fixed in the next milestone release for derived finders.
For your annotated query-method, SDN cannot know what you are referring to with your parameter, so it will not be able to convert it, ever.
Related
I have a "MyInterface" Interface as follows:
public interface MyInterface {
void showStatus();
Map<String,String> getMembers();
}
My "MyClass" class implements this interface and is as follows:
public class MyClass implements MyInterface {
private Map<String,String> members;
public void setMembers(Map<String, String> members) {
this.members = members;
}
public Map<String, String> getMembers() {
return members;
}
}
In my beans file I have set the property tag as follows:
<property name="members">
<map>
<entry key="key1" value="value1"></entry>
</map>
</property>
How does Spring set the value of the members variable, even though the setter method is not defined in the interface?
As jordanpg said, field injection is now discouraged and not proposed in the spring framework reference. But the answer to your question:
How does the property tag in Spring Beans set the value for the private member?
Is :
by using reflection.
This is not stated in the documentation but you can see it by inspecting the source code of the spring framework. Such as in the inject method of the InjectedElement static inner class of InjectionMetadata:
protected void inject(Object target,
#Nullable String requestingBeanName,
#Nullable PropertyValues pvs)
throws Throwable {
if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
field.set(target, getResourceToInject(target, requestingBeanName));
}
Field injection: http://vojtechruzicka.com/field-dependency-injection-considered-harmful/
Still supported by Spring, but not even documented anymore. I assume it's on a long-term deprecation roadmap, but in my experience lots of people still use it in spite of the mountains of recommendations not to.
I wrote a an attribute converter. I want to apply that in an entity. I'm following a purely XML approach so far.
I could not find an equivalent of #Convert in hbm notation.
An example would be appreciated.
When I search for this, understandably, Google returns lots of results about tools/methods on "Auto Converting hbm files to entities vice versa".
Edit:
Now I'm suspecting if there is an option in hbm file, given that this is JPA annotation.
The doc of #Convert says:
The Convert annotation is used to specify the conversion of a Basic
field or property. It is not necessary to use the Basic annotation or
corresponding XML element to specify the basic type.
I'm not entirely sure what it means. Is mixing annotation and XML a way to go in this case?
I've tried this:
public class Person {
//this is enum
private Ethnicity ethnicity;
//.....
}
public enum Ethnicity{
INDIAN("IND"),
PERSIAN("PER")
//...constructors and value field.
public String value(){
return this.value;
}
public Ethnicity fromValue(String value){
//logic for conversion
}
}
Converter:
#Converter
public class EthnicityConverter implements AttributeConverter<Ethnicity,String> {
#Override
public Ethnicity convertToEntityAttribute(String attribute) {
if ( attribute == null ) {
return null;
}
return Ethnicity.fromValue( attribute );
}
#Override
public String convertToDatabaseColumn(Ethnicity dbData) {
if ( dbData == null ) {
return null;
}
return dbData.value();
}
}
HBM File:
//....other columns
<property name="ethnicity">
<column name="ethnicity"/>
<type name="EthnicityConverter"/>
</property>
//....other columns
Edit: Corrected the converter code.
The answer from Sarvana is close - you do in fact use the type XML attribute. However, type is used to name a Hibernate Type. However there is a convention to name, instead, an AttributeConverter - simply apply the prefix converted:: to your AttributeConverter FQN. E.g.,
<property name="ethnicity">
<column name="ethnicity"/>
<type name="converted::EthnicityConverter"/>
</property>
The other option is to auto-apply the converter:
#Converter( autoApply=true)
public class EthnicityConverter implements AttributeConverter<Ethnicity,String> {
...
}
Given the converter above, so long as Hibernate knows about it, Hibernate will apply that to any attribute of type Ethnicity.
HTH
type is the equivalent xml attribute for Convert annotation.
Below is to convert to Y/N in DB and Boolean in entity.
<property name="status" column="book_status" type="yes_no" not-null="true"/>
Just replace yes_no with your custom converter class
Please see my answer at
https://stackoverflow.com/a/37914271/3344829
Official documentation
https://docs.jboss.org/hibernate/orm/4.2/manual/en-US/html/ch06.html
Update
<property name="ethnicity" column="ethnicity" type="com.example.EthnicityConverter"/>
Update
#Converter
public class EthnicityConverter implements AttributeConverter<Ethnicity, String> {
#Override
public String convertToDatabaseColumn(Ethnicity attribute) {
// TODO return String value of enum
}
#Override
public Ethnicity convertToEntityAttribute(String dbData) {
// TODO return resolved enum from string
}
}
I too had to face this issue and i was able to resolve it.
Refer : Hibernate 5 Documentation Example 33. HBM mapping for AttributeConverter
We have to use exact class with package.
Ex :
<property name="ethnicity" column="ethnicity" type="converted::com.example.EthnicityConverter"/>
I would like to secure my services layer using Spring Security. As explained in the documentation, I need to use a MethodSecurityInterceptor that will check if the method invocation is allowed.
To decide if a service method invocation is allowed for a given user, affecting a required role to the invoked method (using MethodSecurityMetadataSource) is not enough for me since it also depends on the parameters passed to the method. As suggested in the documentation, I can write a custom AccessDecisionVoter and access the arguments though the secured object (MethodInvocation in this case).
But, my authorization logic is different across the methods. For example, the arguments may be different between multiple methods and the authorization logic will also be different.
I see two options:
I can use conditional logic in the AccessDecisionVoter to determine the invoked method and the authorization logic to use, but it seems to be an ugly solution.
I can define one MethodSecurityInterceptor per method to secure. According to the Spring documentation, a MethodSecurityInterceptor is used to secure many methods, so it makes me thinking there is another way.
The same question exists for access decision after method invocation (using AfterInvocationProvider).
What are the alternatives?
I achieved that by implementing my own AccessDecisionManager that delegates access decisions to my special interface AccessDecisionStrategy:
public interface AccessDecisionStrategy {
void decide(Authentication authentication, MethodInvocation methodInvocation, ConfigAttribute configAttribute);
}
Each access decision strategy represents different way of making access decision.
You can easily implement your own strategy (even in other language - for instance Scala):
public class SomeStrategy implements AccessDecisionStrategy { ...
As you can see, my AccessDecisionManager has a map of strategies. Strategy used by manager is based on annotation argument.
public class MethodSecurityAccessDecisionManager implements AccessDecisionManager {
private Map<String, AccessDecisionStrategy> strategyMap;
public MethodSecurityAccessDecisionManager(Map<String, AccessDecisionStrategy> strategyMap) {
this.strategyMap = strategyMap;
}
#Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
ConfigAttribute configAttribute = getSingleConfigAttribute(configAttributes);
AccessDecisionStrategy accessDecisionStrategy = strategyMap.get(configAttribute.getAttribute());
if (accessDecisionStrategy == null) {
throw new IllegalStateException("AccessDecisionStrategy with name "
+ configAttribute.getAttribute() + " was not found!");
}
try {
accessDecisionStrategy.decide(authentication, (MethodInvocation) object, configAttribute);
} catch (ClassCastException e) {
throw new IllegalStateException();
}
}
private ConfigAttribute getSingleConfigAttribute(Collection<ConfigAttribute> configAttributes) {
if (configAttributes == null || configAttributes.size() != 1) {
throw new IllegalStateException("Invalid config attribute configuration");
}
return configAttributes.iterator().next();
}
#Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
#Override
public boolean supports(Class<?> clazz) {
return clazz.equals(MethodInvocation.class);
}
}
Now when I want to protect my method I put #Secured annotation with argument that is name of the strategy:
#Secured("GetByOwner")
FlightSpotting getFlightSpotting(Long id);
You can implement and configure as many strategies as you want:
<bean id="methodSecurityAccessDecisionManager"
class="some.package.MethodSecurityAccessDecisionManager">
<constructor-arg>
<map>
<entry key="GetByOwner">
<bean class="some.package.GetByOwnerStrategy"/>
</entry>
<entry key="SomeOther">
<bean class="some.package.SomeOtherStrategy"/>
</entry>
</map>
</constructor-arg>
</bean>
To inject that access decision manager you type:
<sec:global-method-security secured-annotations="enabled"
access-decision-manager-ref="methodSecurityAccessDecisionManager">
</sec:global-method-security>
I also implemented helper class to handle MethodInvocation arguments:
import org.aopalliance.intercept.MethodInvocation;
public class MethodInvocationExtractor<ArgumentType> {
private MethodInvocation methodInvocation;
public MethodInvocationExtractor(MethodInvocation methodInvocation) {
this.methodInvocation = methodInvocation;
}
public ArgumentType getArg(int num) {
try {
Object[] arguments = methodInvocation.getArguments();
return (ArgumentType) arguments[num];
} catch (ClassCastException | ArrayIndexOutOfBoundsException e) {
throw new IllegalStateException();
}
}
}
Now you can easily extract interesting arguments in the code of your strategy to make decision:
Let's say I want to get argument number 0 that is of type Long:
MethodInvocationExtractor<Long> extractor = new MethodInvocationExtractor<>(methodInvocation);
Long id = extractor.getArg(0);
You can implement your own method security annotations based on Spring #PreAuthorize("") construction.
To fetch extra information about the method(beyond method argument values) to SpEL evaluation context you can implement your own MethodSecurityExpressionHandler
#Service
public class MySecurityExpressionHandler extends
DefaultMethodSecurityExpressionHandler {
#Override
public StandardEvaluationContext createEvaluationContextInternal(
Authentication auth, MethodInvocation mi) {
StandardEvaluationContext evaluationContext = super
.createEvaluationContextInternal(auth, mi);
SomeMethodInfoData methodInfoData = mi.getMethod(). ...;
evaluationContext.setVariable("someData", <value computed based on method info data>);
}
return evaluationContext;
}
and register it in your global-method-security declaration
<security:global-method-security
pre-post-annotations="enabled">
<security:expression-handler
ref="mySecurityExpressionHandler" />
</security:global-method-security>
Now you can create custom security annotations(and extra process annotation data in MySecurityExpressionHandler if required)
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#PreAuthorize("#<someData>")
public #interface CustomSecurityAnnotation { ... }
for example you can create a custom annotation to check user roles without messing with strings:
#MyUserRoleCheck(MyAppRole.Admin)
public void someMethod()
I have to create a bean where it needs to be cached based on the dynamic constructor value. Example: I need an OrganizationResource bean where "x" (constructor value) organization will have its own specific instance values and "y" (constructor value) will have different values.
But I don't want to create a new object for every x value, I want it to be cached.
I know there are 2 scopes, singleton and prototype, for dynamic constructor value. I am planning to use prototype, but it seems it will create a new object every time, how can I implement cache based on constructor value in spring?
FactoryBean is a way to go. It is very simple, give it a try. All you have to do is create a class implementing FactoryBean and reference it in bean definition file:
package some.package;
import org.springframework.beans.factory.FactoryBean;
public class ExampleFactory implements FactoryBean {
private String type;
public Object getObject() throws Exception {
//Logic to return beans based on 'type'
}
public Class getObjectType() {
return YourBaseType.class;
}
public boolean isSingleton() {
//set false to make sure Spring will not cache instances for you.
return false;
}
public void setType(final String type) {
this.type = type;
}}
Now, in your bean definition file, put:
<bean id="cached1" class="some.package.ExampleFactory">
<property name="type" value="X" />
</bean>
<bean id="cached2" class="some.package.ExampleFactory">
<property name="type" value="Y" />
</bean>
It will make objects based on strategy you implemented in ExampleFactory.getObject().
Given a set of classes wired together by spring. There are several classes that are used with different configuration in multiple instances in the environment. They have different beanid of course.
The problems:
When they make log entries, we dont know exactly which bean made the log, since the log4j displays the classname only
I know that I could use logger instantiated by spring InitializationBean+BeanNameAware interface methods, but I do not want to do it, since I do not want to implement them in all classes
The solution could be:
Having some effect on bean factory to store the id of the beans in a map with the bean reference (key is the ref, name is the value)
Creating an aspect to be applied on every method, that would set an "BeanName" MDC entry in Log4j before the call, and would restore it to the previous value after the call. Meanwhile the previous beannames could be stored in a threadlocal in a stack.
The questions:
How can I change/configure the bean factory to do this trick for me? Is there any customization point I could use to this aim?
How can I avoid memory leaks in the map in the beanid registry? Maybe the registry is not needed at all, if somehow spring can look up the id for a reference.
Do you have any better idea, that would not result in changing ten thousand classes?
Thanks in advance.
UPDATE:
- Does anyone have solution for the prototype beans?
I have managed to hack something together based on this Spring AOP Example.
I am not yet up to speed with Spring 3 so I have implemented this using Spring 2.5 - I dare say there are more elegant ways of achieving what you want. I have implemented this using System.out's for simplicity but these could easily be converted to log4j calls.
Initially I create a map between the Spring's bean names and the string representation of the object (InitBean). This map is used inside the MethodInterceptor - I did try making the MethodInterceptor an InitializingBean but the MethodInterceptor stopped working for some reason.
Performing an equals between the bean passed in via the MethodInterceptor and the other beans in the application context did not work. e.g. by using something like "ctx.getBeansOfType(GoBean.class)" inside the MethodInterceptor. I presume this is because the object passed in via the MethodInvocation was a GoBean whereas objects obtained from the application context at this point are proxied (e.g. something like example.GoBean$$EnhancerByCGLIB$$bd27d40e).
This is why I had to resort to a comparison of object string representations (which is not ideal). Also I specifically do not want to activate the MethodInterceptor logic when calling the "toString" method on an object (as since I'm using toString elsewhere leads to infinite loops and StackOverflow).
I hope this is useful,
applicationContext.xml
<beans>
<bean name="initBean" class="example.InitBean"/>
<bean name="methodLoggingInterceptor" class="example.MethodLoggingInterceptor">
<property name="initBean" ref="initBean"/>
</bean>
<bean name="proxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>go*</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>methodLoggingInterceptor</value>
</list>
</property>
</bean>
<bean name="goBean1" class="example.GoBean" />
<bean name="goBean2" class="example.GoBean" />
<bean name="goBean3" class="example.GoBean" />
</beans>
GoBean.java
public class GoBean {
public void execute(){
System.out.println(new Date());
}
}
SimpleTestClass.java
public static void main( String[] args ){
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ArrayList<GoBean> goBeans = new ArrayList<GoBean>();
goBeans.add((GoBean) ctx.getBean("goBean1"));
goBeans.add((GoBean) ctx.getBean("goBean2"));
goBeans.add((GoBean) ctx.getBean("goBean3"));
for(GoBean g: goBeans){
g.execute();
}
}
InitBean.java
public class InitBean implements ApplicationContextAware, InitializingBean {
private ApplicationContext ctx;
private Map<String, String> beanMap = new HashMap<String,String>();
public void setApplicationContext(ApplicationContext ac) throws BeansException {
ctx = ac;
}
public void afterPropertiesSet() throws Exception {
for(String beanName: ctx.getBeanNamesForType(GoBean.class)){
beanMap.put(ctx.getBean(beanName).toString(), beanName);
}
}
public Map<String,String> getBeanMap(){
return beanMap;
}
}
MethodLoggingInterceptor.java
public class MethodLoggingInterceptor implements MethodInterceptor{
private InitBean initBean;
public Object invoke(MethodInvocation method) throws Throwable {
if (!"toString".equals(method.getMethod().getName())) {
StringBuilder sb = new StringBuilder();
Object obj = method.getThis();
if (obj instanceof GoBean) {
Map<String,String> beanMap = initBean.getBeanMap();
String objToString = obj.toString();
if (beanMap.containsKey(objToString)) {
System.out.println(beanMap.get(objToString));
sb.append("bean: ");
sb.append(beanMap.get(objToString));
sb.append(" : ");
}
}
sb.append(method.getMethod().getDeclaringClass());
sb.append('.');
sb.append(method.getMethod().getName());
System.out.println(sb.toString() + " starts");
Object result = method.proceed();
System.out.println(sb.toString() + " finished");
return result;
} else {
return method.proceed();
}
}
public void setInitBean(InitBean ib) {
this.initBean = ib;
}
}