I am new using dependency injection. Can anyone tell me how to configure a servlet to inject a string URI pointing to a file? The method signature is the following:
#Inject
public void setCar(String value)
{
CarUri =value;
}
Thanks in advance!
You can try injecting #Named fields
// inside module
#Provides
#Named("CarURI")
public String carURI() {
return "URI";
}
#Inject
public void setCar(#Named("CarURI") String value) {
CarUri = value;
}
example:
https://www.tutorialspoint.com/guice/guice_field_injection.htm
https://www.tutorialspoint.com/guice/guice_method_injection.htm
Related
I am working within an environment that changes credentials every several minutes. In order for beans that implement clients who depend on these credentials to work, the beans need to be refreshed. I decided that a good approach for that would be implementing a custom scope for it.
After looking around a bit on the documentation I found that the main method for a scope to be implemented is the get method:
public class CyberArkScope implements Scope {
private Map<String, Pair<LocalDateTime, Object>> scopedObjects = new ConcurrentHashMap<>();
private Map<String, Runnable> destructionCallbacks = new ConcurrentHashMap<>();
private Integer scopeRefresh;
public CyberArkScope(Integer scopeRefresh) {
this.scopeRefresh = scopeRefresh;
}
#Override
public Object get(String name, ObjectFactory<?> objectFactory) {
if (!scopedObjects.containsKey(name) || scopedObjects.get(name).getKey()
.isBefore(LocalDateTime.now().minusMinutes(scopeRefresh))) {
scopedObjects.put(name, Pair.of(LocalDateTime.now(), objectFactory.getObject()));
}
return scopedObjects.get(name).getValue();
}
#Override
public Object remove(String name) {
destructionCallbacks.remove(name);
return scopedObjects.remove(name);
}
#Override
public void registerDestructionCallback(String name, Runnable runnable) {
destructionCallbacks.put(name, runnable);
}
#Override
public Object resolveContextualObject(String name) {
return null;
}
#Override
public String getConversationId() {
return "CyberArk";
}
}
#Configuration
#Import(CyberArkScopeConfig.class)
public class TestConfig {
#Bean
#Scope(scopeName = "CyberArk")
public String dateString(){
return LocalDateTime.now().toString();
}
}
#RestController
public class HelloWorld {
#Autowired
private String dateString;
#RequestMapping("/")
public String index() {
return dateString;
}
}
When I debug this implemetation with a simple String scope autowired in a controller I see that the get method is only called once in the startup and never again. So this means that the bean is never again refreshed. Is there something wrong in this behaviour or is that how the get method is supposed to work?
It seems you need to also define the proxyMode which injects an AOP proxy instead of a static reference to a string. Note that the bean class cant be final. This solved it:
#Configuration
#Import(CyberArkScopeConfig.class)
public class TestConfig {
#Bean
#Scope(scopeName = "CyberArk", proxyMode=ScopedProxyMode.TARGET_CLASS)
public NonFinalString dateString(){
return new NonFinalString(LocalDateTime.now());
}
}
I have a configuration object that is managed by Spring. Let's call that object 'ConfigurationObject'. The configuration contained by that object I also want to make accessible, through delegation, in objects which I instantiate with the 'new' operator. Let's call these objects 'UserObject'.
Would it then be acceptable to pass the configurationObject as an argument to the constructor of the UserObject and then assign it to a regular private field that is not managed by Spring? So that I can then use the ConfigurationObject to return configuration form the UserObject. See below for the story in code.
#Configuration
public class ConfigurationObject {
private final String configItem;
public ConfigurationObject(#Value("${config.item}") final String configItem){
this.configItem = configItem;
}
public String getConfigItem() {
return configItem;
}
}
public final class UserObject {
private ConfigurationObject configurationObject;
/* other properties */
public UserObject(final ConfigurationObject configurationObject) {
this.configurationObject = configurationObject;
}
public String getConfigItem(){
return configurationObject.getConfigItem();
}
}
Best regards,
Henk
You can get Spring class using context from ApplicationInitializer:
ApplicationInitializer.getAppContext().getBean(ConfigurationObject.class);
Or create class to get Spring context using ApplicationContextAware:
#Component
public class SpringContext implements ApplicationContextAware {
private static ApplicationContext context;
public static UserService getUserService() {
return (UserService)context.getBean("userService");
}
#Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
// store ApplicationContext reference to access required beans later on
SpringContext.context = context;
}
}
Yes. It is a very valid use-case. I often do it when I need to create an object which some of its properties are determined during the runtime which do not know upfront.
I would suggest creating a factory method on ConfigurationObject for creating an UserObject:
#Configuration
public class ConfigurationObject {
private final String configItem;
public ConfigurationObject(#Value("${config.item}") final String configItem){
this.configItem = configItem;
}
public String getConfigItem() {
return configItem;
}
public UserObject createUserObject(){
return new UserObject(this);
}
}
again a small problem by understanding "how tapestry works".
I've got a Tapestry component (in this case a value encoder):
public class EditionEncoder implements ValueEncoder<Edition>, ValueEncoderFactory<Edition> {
#Inject
private IEditionManager editionDao;
public EditionEncoder(IEditionManager editionDao) {
this.editionManager = editionDao;
}
#Override
public String toClient(Edition value) {
if(value == null) {
return "";
}
return value.getName();
}
#Override
public Edition toValue(String clientValue) {
if(clientValue.equals("")) {
return null;
}
return editionManager.getEditionByName(clientValue);
}
#Override
public ValueEncoder<Edition> create(Class<Edition> type) {
return this;
}
}
Injecting the the Manager is not working, because the Encoder is created within a page like that:
public void create() {
editionEncoder = new EditionEncoder();
}
casued by this, i'm forced to use this ugly solution:
#Inject
private IEditionManager editionmanager;
editionEncoder = new EditionEncoder(editionManager);
Is there a better way to inject components during runtime or is there a better solution in general for it?
Thanks for your help in advance,
As soon as you use "new" then tapestry-ioc is not involved in object creation and can't inject. You should inject everything and never use "new" for singleton services. This is true for all ioc containers, not just tapestry-ioc.
Also if you put #Inject on a field then you don't also need a constructor to set it. Do one or the other, never both.
You should do something like this:
public class MyAppModule {
public void bind(ServiceBinder binder) {
binder.bind(EditionEncoder.class);
}
}
Then in your page/component/service
#Inject EditionEncoder editionEncoder;
If you wanted to put your own instantiated objects in there you can do
public class MyServiceModule {
public void bind(ServiceBinder binder) {
binder.bind(Service1.class, Service1Impl.class);
binder.bind(Service2.class, Service2Impl.class);
}
public SomeService buildSomeService(Service1 service1, Service2 service2, #AutoBuild Service3Impl service3) {
Date someDate = new Date();
return new SomeServiceImpl(service1, service2, service3, someDate);
}
}
I am not being able to make messageSource work in the Pojo classes,its throwing a nullpointerexception. However in all the other classes namely controller,service messageSource is working alright. Could someone please suggest what needs to be done ?
#Autowired
private MessageSource messageSource;
I have autowired the MessageSource using the above code snippet.
public class ProposalWiseSelectionForm implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Autowired
private MessageSource messageSource;
private String txtPageHierarchy="";
private String txtLineOfBusiness;
private String txtProduct;
private String btn;
private String clickedGo="N";
private List arrLineOfBusiness=new ArrayList();
private List arrProduct=new ArrayList();
#Valid
private ArrayList documentList=initiateDocumentList();
private String txtPageMode="I";
private String enableDiscardBtn="N";
private String enableInsertBtn="N";
private String isDivVisible="N";
private int numApplicationType=1;
public ProposalWiseSelectionForm() {
}
public String getTxtPageHierarchy() {
return txtPageHierarchy;
}
public void setTxtPageHierarchy(String txtPageHierarchy) {
this.txtPageHierarchy = txtPageHierarchy;
}
public String getTxtLineOfBusiness() {
return txtLineOfBusiness;
}
public void setTxtLineOfBusiness(String txtLineOfBusiness) {
this.txtLineOfBusiness = txtLineOfBusiness;
}
public String getTxtProduct() {
return txtProduct;
}
public void setTxtProduct(String txtProduct) {
this.txtProduct = txtProduct;
}
public String getBtn() {
return btn;
}
public void setBtn(String btn) {
this.btn = btn;
}
public String getClickedGo() {
return clickedGo;
}
public void setClickedGo(String clickedGo) {
this.clickedGo = clickedGo;
}
public List getArrLineOfBusiness() {
return arrLineOfBusiness;
}
public void setArrLineOfBusiness(List arrLineOfBusiness) {
this.arrLineOfBusiness = arrLineOfBusiness;
}
public List getArrProduct() {
return arrProduct;
}
public void setArrProduct(List arrProduct) {
this.arrProduct = arrProduct;
}
public void setArrProduct(ArrayList arrProduct) {
this.arrProduct = arrProduct;
}
public ArrayList getDocumentList() {
return documentList;
}
public void setDocumentList(ArrayList documentList) {
this.documentList = documentList;
}
public String getTxtPageMode() {
return txtPageMode;
}
public void setTxtPageMode(String txtPageMode) {
this.txtPageMode = txtPageMode;
}
public String getEnableDiscardBtn() {
return enableDiscardBtn;
}
public void setEnableDiscardBtn(String enableDiscardBtn) {
this.enableDiscardBtn = enableDiscardBtn;
}
public String getEnableInsertBtn() {
return enableInsertBtn;
}
public void setEnableInsertBtn(String enableInsertBtn) {
this.enableInsertBtn = enableInsertBtn;
}
public String getIsDivVisible() {
return isDivVisible;
}
public void setIsDivVisible(String isDivVisible) {
this.isDivVisible = isDivVisible;
}
public int getNumApplicationType() {
return numApplicationType;
}
public void setNumApplicationType(int numApplicationType) {
this.numApplicationType = numApplicationType;
}
}
In order to be able to use #Autowired in a class, that class has to be managed by Spring.
of
Your ProposalWiseSelectionForm class is obviously not managed by Spring and therefor messageSource is always null.
Using #Autowired MessageSource messageSource in your other classes works, because as you mention those classes are managed by Spring (as you have mentioned they are either controllers, services etc).
I am guessing that ProposalWiseSelectionForm is a DTO used to capture values from a form. The sort of class will not be a Spring bean and therefor you can't autowire stuff into it.
I suggest you either move the logic you need out of the DTO and into the controller (or some Spring managed utility) or in the extreme case that you absolutely need #Autowired in the DTO, take a look at #Configurable here and here
Try using #Component,you might be getting this issue because of the fact the Pojo class is not being recognized.
You have to make your class a Spring bean
Add #Component annotation to your class and add these 2 lines to your appContext.xml:
<context:component-scan base-package="com.<your-company-name>" />
<context:annotation-config />
Or just add the service in your beans section in the appContext.xml if you wish not to work with Spring component-scan feature.
I have a java class like :
class TestJsonClass {
private String propertyA;
private String propertyB;
private String propertyC;
}
Now during runtime i want to give different property names for each of the property, and not a static one using #JsonProperty("sample")
How do I accomplish this? I am using Jackson library ad Spring MVC
Thanks in advance...
You can make use of Modules for this purpose. This is the easiest solutions to your problem. Here is an example:
A simple class that can carry your property-name-mappings for each request:
public class PropertyNameMapper {
// The class for which the mappings need to take place.
public Class<?> classToFilter;
// The mappings property names. Key would be the existing property name
// value would be name you want in the ouput.
public Map<String, String> nameMappings = Collections.emptyMap();
public PropertyNameMapper(Class<?> classToFilter, Map<String, String> nameMappings) {
this.classToFilter = classToFilter;
this.nameMappings = nameMappings;
}
}
A custom BeanPropertyWriter that will be used for specifying the output name for the properties.
public class MyBeanPropertyWriter extends BeanPropertyWriter {
// We would just use the copy-constructor rather than modifying the
// protected properties. This is more in line with the current design
// of the BeanSerializerModifier class (according to its documentation).
protected MyBeanPropertyWriter(BeanPropertyWriter base, String targetName) {
super(base, new SerializedString(targetName));
}
}
Now, a custom BeanSerializerModifier that is called each time to allow you to modify the serialized properties.
public class MySerializerModifier extends BeanSerializerModifier {
public List<BeanPropertyWriter> changeProperties(
SerializationConfig config, BeanDescription beanDesc,
List<BeanPropertyWriter> beanProperties) {
List<PropertyNameMapper> propertyMappings = getNameMappingsFromRequest();
PropertyNameMapper mapping = mappingsForClass(propertyMappings,
beanDesc.getBeanClass());
if (mapping == null) {
return beanProperties;
}
List<BeanPropertyWriter> propsToWrite = new ArrayList<BeanPropertyWriter>();
for (BeanPropertyWriter propWriter : beanProperties) {
String propName = propWriter.getName();
String outputName = mapping.nameMappings.get(propName);
if (outputName != null) {
BeanPropertyWriter modifiedWriter = new MyBeanPropertyWriter(
propWriter, outputName);
propsToWrite.add(modifiedWriter);
} else {
propsToWrite.add(propWriter);
}
}
return propsToWrite;
}
private List<PropertyNameMapper> getNameMappingsFromRequest() {
RequestAttributes requestAttribs = RequestContextHolder
.getRequestAttributes();
List<PropertyNameMapper> nameMappings = (List<PropertyNameMapper>) requestAttribs
.getAttribute("nameMappings",
RequestAttributes.SCOPE_REQUEST);
return nameMappings;
}
private PropertyNameMapper mappingsForClass(
List<PropertyNameMapper> nameMappings, Class<?> beanClass) {
for (PropertyNameMapper mapping : nameMappings) {
if (mapping.classToFilter.equals(beanClass)) {
return mapping;
}
}
return null;
}
}
Now, you need a custom Module to be able to customize the output using the above created BeanSerializerModifier:
public class MyModule extends Module {
#Override
public String getModuleName() {
return "Test Module";
}
#Override
public void setupModule(SetupContext context) {
context.addBeanSerializerModifier(new MySerializerModifier());
}
#Override
public Version version() {
// Modify if you need to.
return Version.unknownVersion();
}
}
Now register this module with your ObjectMapper. You can get the Jackson HTTP message converter from your spring application context, and get its object mapper.
// Figure out a way to get the ObjectMapper.
MappingJackson2HttpMessageConverter converter = ... // get the jackson-mapper;
converter.getObjectMapper().registerModule(new MyModule())
And that's it. This is the easiest way to customize serialization of your properties dynamically.
To use this, create a List of PropertyNameMappers and add it as an attribute (named "nameMappings" in this example) in the current request.
This is an example, not production-ready code. You might probably need to add null-checks and things like that. Also, a few minor adjustments might be needed based on the version of the libraries you are using.
If the solution doesn't work for you, let me know the problems you are facing.
You could inject a custom PropertyNamingStrategy into the ObjectMapper that's used in deserialization.
Just set fields into the PropertyNamingStrategy at runtime, assuming you can map them to something like the default JsonPropertyName (e.g. propertyA, propertyB, propertyC).
public class MyNamingStrategy extends PropertyNamingStrategy {
String propertyAName, propertyBName, propertyCName;
public MyNamingStrategy(String propANm, String propBNm, String propCNm) {
this.propertyAName = propANm;
//finish
}
#Override
public String nameForField(MapperConfig<?> config, AnnotatedField field,
String defaultName) {
return convert(defaultName);
}
#Override
public String nameForGetterMethod(MapperConfig<?> config,
AnnotatedMethod method, String defaultName) {
return convert(defaultName);
}
#Override
public String nameForSetterMethod(MapperConfig<?> config,
AnnotatedMethod method, String defaultName) {
return convert(defaultName);
}
public String convert(String defaultName ){
return defaultName.replace("propertyA", propertyAName).replace( //finish
}
Finally you'd create an instance and inject it at runtime.
objectMapper.setNamingStrategy(myNamingStrategyInstance));
See this Cowtowncoder post for more on PropertyNamingStrategy:
Jackson 1.8: custom property naming strategies
Or this documentation:
github.com/FasterXML/jackson-docs/wiki/PropertyNamingStrategy