In grails 3 is there a way to bind time of format "11:00 AM" to java.sql.Time?
import java.sql.Time
Time startTime
There are several ways to do it. One is to supply an appopriate ValueConverter as described in the Custom Data Converters section at http://docs.grails.org/3.3.8/guide/theWebLayer.html#dataBinding.
That could look something like this...
package com.myapp.converters
import grails.databinding.converters.ValueConverter
import java.sql.Time
/**
* A custom converter which will convert String into a Time object.
*/
class TimeValueConverter implements ValueConverter {
boolean canConvert(value) {
value instanceof String
}
def convert(value) {
// return a new Time instance initialized with the `value` parameter
}
Class<?> getTargetType() {
java.sql.Time
}
}
Then add an instance of that class the Spring application context:
beans = {
timeConverter com.myapp.converters.TimeValueConverter
// ...
}
Related
I am trying to create nodes of a specific type with properties which can be dynamic .
For Example : I can create a Person node with name,age,address properties. But these need not be the only properties when I create another Person node. This node can have name,age,address and an additional property salary. Using spring data or query DSL needs me to create Java POJO class Person with fixed number of instance variables name,age and address .
#NodeEntity
public class Person {
#GraphId private Long id;
private String name;
private String age;
private String address;
}
I cannot add a dynamic property for salary for another Person node. Is there a way I can achieve this ?
Dynamic properties are not supported in Neo4j-OGM at the moment (see https://jira.spring.io/browse/DATAGRAPH-555)
If you only interact with your graph via the OGM and do not have to query on individual dynamic properties, you could try a Map of properties with a custom Converter, that converts this Map to a String (like json). The OGM will then use this converter to serialize the map to and from the graph.
Note that because the values are squashed into a String, it is now not trivial to query on an individual dynamic property.
To create a custom converter you need to implement org.neo4j.ogm.typeconversion.AttributeConverter and provide the implementation to convert from a Map to String.
Then, annotate your map property in your domain entity like this:
#Convert(MoneyConverter.class)
Edit:
As pointed out by Michael, if the salary is the only extra optional property, then it makes sense to have this property but set it only when it has a value. Dynamic properties are overkill in this case. You may want to use dynamic properties when you have an unknown and arbitrary set of properties to be persisted with the node
You can workaround the limitations by creating a CompositeAttributeConverter saving each dynamic property in the graph (not only as JSON-String wich cannot be queried well - as mentioned by luanne in the accepted answer)
import java.lang.reflect.Field;
import java.util.*;
import org.neo4j.ogm.typeconversion.CompositeAttributeConverter;
public abstract class DynamicPropertiesConverter implements CompositeAttributeConverter<Map<String, ?>> {
private Set<String> blacklist;
public DynamicPropertiesConverter(Class<?> clazz) {
blacklist = new HashSet<>();
addAllFields(clazz);
}
public DynamicPropertiesConverter(Set<String> blacklist) {
this.blacklist = blacklist;
}
public void addAllFields(Class<?> type) {
for (Field field : type.getDeclaredFields()) {
blacklist.add(field.getName());
}
if (type.getSuperclass() != null) {
addAllFields(type.getSuperclass());
}
}
#Override
public Map<String, ?> toGraphProperties(Map<String, ?> value) {
Map<String, ?> result = new HashMap<>(value);
result.keySet().removeAll(blacklist);
return result;
}
#Override
public Map<String, ?> toEntityAttribute(Map<String, ?> value) {
return toGraphProperties(value);
}
}
Now you can create a special version of this converter:
public class DynamicNodePropertiesConverter extends DynamicPropertiesConverter {
public DynamicNodePropertiesConverter() {
super(Node.class);
}
}
And use it like this:
import java.util.Map;
import DynamicNodePropertiesConverter;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Relationship;
import org.neo4j.ogm.annotation.typeconversion.Convert;
#NodeEntity
public class Node {
#Convert(DynamicNodePropertiesConverter.class)
private Map<String, Object> data;
/* getter and setter */
}
I initially had my #NodeEntity class having a #GraphProperty of java.util.Date type. The graph repository APIs automatically convert that to long / string value and stores it based on my property type.
As I wanted to import huge chunk of data from csv, I wanted this date field in my custom or pre-defined string format, say "yyyyMMdd". So I wrote my spring converter factories for both String -> Date and DAte -> String and registered them in the spring xml for conversion service. But unfortunately my converter was never called. Only the standard converter was called.
Later, when I wrap the date object inside MyDate class and changed the converter to String -> MyDAte and vice versa instead of java.util.Date, converter was called and the required serialization was done.
I dont want this MyDate wrapper around Date just for the sake of converter. Now, my question is, how to override the default date converter with my converters?
try this:
#Configuration
#EnableNeo4jRepositories
static class TestConfig extends Neo4jConfiguration {
#Bean
GraphDatabaseService graphDatabaseService() {
return new ImpermanentGraphDatabase();
}
#Bean
protected ConversionService neo4jConversionService() throws Exception {
ConversionService conversionService = super.neo4jConversionService();
ConverterRegistry registry = (ConverterRegistry) conversionService;
registry.removeConvertible(Date.class, String.class);
registry.removeConvertible(String.class, Date.class);
//add your own converters like this
registry.addConverter(new MyDateToStringConverter());
registry.addConverter(new MyStringToDateConverter());
return conversionService;
}
}
Can we create a Custom LifeCycle using StructureMap wherein the object has to be in Singleton scope for specified preiod of time, after which the object has to be created again. In short, can we create objects every 20 or 30 mins.
Sure, see e.g. http://www.mikeobrien.net/blog/creating-structuremap-lifecycle-for-wcf/ for an example of how to implement ILifecycle (in this case backed by WCF, but you can just as well make it thread-local, or static). You'll just have to add the logic to return a new IObjectCache instance after x minutes have passed.
Copy/paste of the code there:
public class WcfOperationLifecycle : ILifecycle
{
public static readonly string ITEM_NAME = "STRUCTUREMAP-INSTANCES";
public void EjectAll()
{
FindCache().DisposeAndClear();
}
public IObjectCache FindCache()
{
if (!OperationContext.Current.OutgoingMessageProperties.ContainsKey(ITEM_NAME))
OperationContext.Current.OutgoingMessageProperties.Add(ITEM_NAME, new MainObjectCache());
return (IObjectCache)OperationContext.Current.OutgoingMessageProperties[ITEM_NAME];
}
public string Scope { get { return "WcfOperationLifecycle"; } }
}
I'm trying to port the JSF #ViewScoped annotation to CDI. The reason is more educational rather than based on need. I chose this particular scope mainly due to the lack of a better concrete example of a custom scope one might want to implement in CDI.
That said, my starting point was Porting the #ViewScoped JSF annotation to CDI. But, this implementation does not take into account a seemingly very important responsibility of Context (i.e. destroying) mentioned in the API:
The context object is responsible for creating and destroying contextual instances by calling operations of Contextual. In particular, the context object is responsible for destroying any contextual instance it creates by passing the instance to Contextual.destroy(Object, CreationalContext). A destroyed instance must not subsequently be returned by get(). The context object must pass the same instance of CreationalContext to Contextual.destroy() that it passed to Contextual.create() when it created the instance.
I decided to add this functionality by having my Context object:
keep track of what Contextual objects it creates for which UIViewRoots;
implement the ViewMapListener interface and register itself as listener for each UIViewRoot by calling UIViewRoot.subscribeToViewEvent(PreDestroyViewMapEvent.class, this);
destroy any created Contextuals when the ViewMapListener.processEvent(SystemEvent event) is called and unregister itself from that UIViewRoot.
Here's my Context implementation:
package com.example;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import javax.enterprise.context.spi.Context;
import javax.enterprise.context.spi.Contextual;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.PreDestroyViewMapEvent;
import javax.faces.event.SystemEvent;
import javax.faces.event.ViewMapListener;
public class ViewContext implements Context, ViewMapListener {
private Map<UIViewRoot, Set<Disposable>> state;
public ViewContext() {
this.state = new HashMap<UIViewRoot, Set<Disposable>>();
}
// mimics a multimap put()
private void put(UIViewRoot key, Disposable value) {
if (this.state.containsKey(key)) {
this.state.get(key).add(value);
} else {
HashSet<Disposable> valueSet = new HashSet<Disposable>(1);
valueSet.add(value);
this.state.put(key, valueSet);
}
}
#Override
public Class<? extends Annotation> getScope() {
return ViewScoped.class;
}
#Override
public <T> T get(final Contextual<T> contextual,
final CreationalContext<T> creationalContext) {
if (contextual instanceof Bean) {
Bean bean = (Bean) contextual;
String name = bean.getName();
FacesContext ctx = FacesContext.getCurrentInstance();
UIViewRoot viewRoot = ctx.getViewRoot();
Map<String, Object> viewMap = viewRoot.getViewMap();
if (viewMap.containsKey(name)) {
return (T) viewMap.get(name);
} else {
final T instance = contextual.create(creationalContext);
viewMap.put(name, instance);
// register for events
viewRoot.subscribeToViewEvent(
PreDestroyViewMapEvent.class, this);
// allows us to properly couple the right contaxtual, instance, and creational context
this.put(viewRoot, new Disposable() {
#Override
public void dispose() {
contextual.destroy(instance, creationalContext);
}
});
return instance;
}
} else {
return null;
}
}
#Override
public <T> T get(Contextual<T> contextual) {
if (contextual instanceof Bean) {
Bean bean = (Bean) contextual;
String name = bean.getName();
FacesContext ctx = FacesContext.getCurrentInstance();
UIViewRoot viewRoot = ctx.getViewRoot();
Map<String, Object> viewMap = viewRoot.getViewMap();
if (viewMap.containsKey(name)) {
return (T) viewMap.get(name);
} else {
return null;
}
} else {
return null;
}
}
// this scope is only active when a FacesContext with a UIViewRoot exists
#Override
public boolean isActive() {
FacesContext ctx = FacesContext.getCurrentInstance();
if (ctx == null) {
return false;
} else {
UIViewRoot viewRoot = ctx.getViewRoot();
return viewRoot != null;
}
}
// dispose all of the beans associated with the UIViewRoot that fired this event
#Override
public void processEvent(SystemEvent event)
throws AbortProcessingException {
if (event instanceof PreDestroyViewMapEvent) {
UIViewRoot viewRoot = (UIViewRoot) event.getSource();
if (this.state.containsKey(viewRoot)) {
Set<Disposable> valueSet = this.state.remove(viewRoot);
for (Disposable disposable : valueSet) {
disposable.dispose();
}
viewRoot.unsubscribeFromViewEvent(
PreDestroyViewMapEvent.class, this);
}
}
}
#Override
public boolean isListenerForSource(Object source) {
return source instanceof UIViewRoot;
}
}
Here's the Disposable interface:
package com.example;
public interface Disposable {
public void dispose();
}
Here's the scope annotation:
package com.example;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.enterprise.context.NormalScope;
#Inherited
#NormalScope
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE, ElementType.METHOD,
ElementType.FIELD, ElementType.PARAMETER})
public #interface ViewScoped {
}
Here's the CDI extension declaration:
package com.example;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.Extension;
public class CustomContextsExtension implements Extension {
public void afterBeanDiscovery(#Observes AfterBeanDiscovery event) {
event.addContext(new ViewContext());
}
}
I added the javax.enterprise.inject.spi.Extension file under META-INF/services containing com.example.CustomContextsExtension to properly register the above with CDI.
I can now make beans like (notice the use of the custom #ViewScoped implementation.):
package com.example;
import com.concensus.athena.framework.cdi.extension.ViewScoped;
import java.io.Serializable;
import javax.inject.Named;
#Named
#ViewScoped
public class User implements Serializable {
...
}
The beans are created properly and properly injected into JSF pages (i.e. the same instance is returned per view, new ones are created only when the view is created, the same instances are injected over multiple requests to the same view). How do I know? Imagine the above code littered with debugging code which I purposefully stripped out for clarity and since this is already a huge post.
The problem is that my ViewContext.isListenerForSource(Object source) and ViewContext.processEvent(SystemEvent event) are never called. I was expecting that at least upon session expiration those events would be called, since the view map is stored in the session map (correct?). I set the session timeout to 1 minute, waited, saw the timeout happen, but my listener was still not called.
I also tried adding the following to my faces-config.xml (mostly out of the lack of ideas):
<system-event-listener>
<system-event-listener-class>com.example.ViewContext</system-event-listener-class>
<system-event-class>javax.faces.event.PreDestroyViewMapEvent</system-event-class>
<source-class>javax.faces.component.UIViewRoot</source-class>
</system-event-listener>
Finally, my environment is JBoss AS 7.1.1 with Mojarra 2.1.7.
Any clues would be greatly appreciated.
EDIT: Further Investigation.
PreDestroyViewMapEvent doesn't seem to be fired at all while PostConstructViewMapEvent is fired as expected - every time a new view map is created, specifically during UIViewRoot.getViewMap(true). The documentation states that PreDestroyViewMapEvent should be fired every time clear() is called on the view map. That leaves to wonder - is clear() required to be called at all? If so, when?
The only place in the documentation that I was able to find such a requirement is in FacesContext.setViewRoot():
If the current UIViewRoot is non-null, and calling equals() on the
argument root, passing the current UIViewRoot returns false, the clear
method must be called on the Map returned from UIViewRoot#getViewMap.
Does this ever happen in the normal JSF lifecycle, i.e. without programmatically calling UIViewRoot.setViewMap()? I can't seem to find any indication.
This is related to an issue with the JSF spec that is being fixed in the JSF2.2 spec, see here. Also, I created an issue with Apache DeltaSpike so they may try to fix it, see here. If it's fixed in DeltaSpike, then it may end up being merged into CODI and / or Seam as well.
The view map is stored in a LRU map, because you never know which view will be post back. Unfortunately, the PreDestroyViewMapEvent is not called before removing from this map.
A workaround is to reference your object from within a WeakReference. You can use ReferenceQueue or check the reference when to call your destruction code.
I'm new to Guice and here is a naive question. I learned that we could bind String to a particular value through:
bind(String.class)
.annotatedWith(Names.named("JDBC URL"))
.toInstance("jdbc:mysql://localhost/pizza");
But what if I want to bind String to any possible characters?
Or I think it could be described this way:
How can I replace "new SomeClass(String strParameter)" with Guice?
You first need to annotate the constructor for SomeClass:
class SomeClass {
#Inject
SomeClass(#Named("JDBC URL") String jdbcUrl) {
this.jdbcUrl = jdbcUrl;
}
}
I prefer to use custom annotations, like this:
class SomeClass {
#Inject
SomeClass(#JdbcUrl String jdbcUrl) {
this.jdbcUrl = jdbcUrl;
}
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD, ElementType.PARAMETER})
#BindingAnnotation
public #interface JdbcUrl {}
}
Then you need to provide a binding in your Module:
public class SomeModule extends AbstractModule {
private final String jdbcUrl; // set in constructor
protected void configure() {
bindConstant().annotatedWith(SomeClass.JdbcUrl.class).to(jdbcUrl);
}
}
Then an time Guice creates SomeClass, it will inject the parameter. For instance, if SomeOtherClass depends on SomeClass:
class SomeOtherClass {
#Inject
SomeOtherClass(SomeClass someClass) {
this.someClass = someClass;
}
Often, when you think you want to inject a String, you want to inject an object. For instance, if the String is a URL, I often inject a URI with a binding annotation.
This all assumes there is some constant value you can define at module creation time for the String. If the value isn't available at module creation time, you can use AssistedInject.
This might be off-topic, but Guice makes configuration much easier than writing an explicit binding for every String you need. You can just have a config file for them:
Properties configProps = Properties.load(getClass().getClassLoader().getResourceAsStream("myconfig.properties");
Names.bindProperties(binder(), configProps);
and voilĂ all your config is ready for injection:
#Provides // use this to have nice creation methods in modules
public Connection getDBConnection(#Named("dbConnection") String connectionStr,
#Named("dbUser") String user,
#Named("dbPw") String pw,) {
return DriverManager.getConnection(connectionStr, user, pw);
}
Now just create your Java properties file myconfig.properties at the root of your classpath with
dbConnection = jdbc:mysql://localhost/test
dbUser = username
dbPw = password
or merge authorization information from some other source into the properties and you're set.
I was able to inject a string through Named annotation.
#Provides
#Named("stage")
String stage() {
return domain;
}
class SomeClass {
#Inject
#Named("stage")
String stageName;
}
I find a solution in the FAQ of Guice:
http://code.google.com/docreader/#p=google-guice&s=google-guice&t=FrequentlyAskedQuestions
In addition to define an annotation and a String attribute in MyModule, I need to write below line to get a instance of SomeClass:
SomeClass instance = Guice.createInjector(new MyModule("any string i like to use")).getInstance(SomeClass.class);
But I remembered that Injector.getInstance() should not be used except for the root object, so is there any better way to do this?