injecting enum(Spring) - java

I have an enum and I need to inject it with spring bean.
my enum is:
public enum Status {
IN_PROCESS(1,"In process"),
DONE(0,"Successful"),
CANNOT_DONE(2,"Unsuccessful");
private final int code;
private final String description;
private Status(int code, String description){
this.code = code;
this.description = description;
}
public int getCode() {
return code;
}
public String getDescription() {
return description;
}
}
what my bean.xml should look like for this enum..
thanks.

You can not create an Enum via its constructor from outside of this Enum (not in java and not in Spring) because Enum values are constants!
An Enum constructor can only be invoked from the Enum declarion itselve.
Of course you can use an instance of this Enum, even in Spring, but you can not create it:
public Class Entity {
public Entity(Status status) {...}
}
<bean name="entity" class="package.Entity">
<property name="status" value="IN_PROCESS" />
</bean>

Technically you may try to register enum as a bean like this:
#Configuration
class EnumProducer {
#Bean
Status inProgress() {
return Status.IN_PROGRESS;
}
}
and then inject it like:
#Autowired("inProgress") Status status.
But there is no any sense for doing it.

Check <util:constant/> here:
http://static.springsource.org/spring/docs/3.0.x/reference/xsd-config.html

Related

Java Object mapping framework working with builder pattern

Is there any class mapping framework which works with builders? I would like to keep some of my classes immutable and avoid multiple constructors - the Builder Pattern comes to the rescue. However I can't any mapping framework which would use builder automatically instead of getters/setters.
I got the following working with Lombok and ModelMapper. See: http://modelmapper.org/getting-started/
public class MyService {
private ModelMapper modelMapper;
public MyService(){
this.modelMapper = new ModelMapper();
this.modelMapper.getConfiguration()
.setMatchingStrategy(MatchingStrategies.STRICT)
.setDestinationNamingConvention(LombokBuilderNamingConvention.INSTANCE)
.setDestinationNameTransformer(LombokBuilderNameTransformer.INSTANCE);
}
public OutputDTO aMethod(final InputDTO input){
return modelMapper.map(input, OutputDTO.OutputDTOBuilder.class).build();
}
}
Where LombokBuilderNamingConvention is:
import org.modelmapper.spi.NamingConvention;
import org.modelmapper.spi.PropertyType;
public class LombokBuilderNamingConvention implements NamingConvention {
public static LombokBuilderNamingConvention INSTANCE = new LombokBuilderNamingConvention();
#Override
public boolean applies(String propertyName, PropertyType propertyType) {
return PropertyType.METHOD.equals(propertyType);
}
#Override
public String toString() {
return "Lombok #Builder Naming Convention";
}
}
And LombokBuilderNameTransformer is:
import org.modelmapper.spi.NameTransformer;
import org.modelmapper.spi.NameableType;
public class LombokBuilderNameTransformer implements NameTransformer {
public static final NameTransformer INSTANCE = new LombokBuilderNameTransformer();
#Override
public String transform(final String name, final NameableType nameableType) {
return Strings.decapitalize(name);
}
#Override
public String toString() {
return "Lombok #Builder Mutator";
}
}
And OutputDTO can look like:
#Builder // Has .builder() static method
#Value // Thus immutable
public class OutputDTO {
private String foo;
private int bar;
}
This can be easily done with MapStruct and using a custom naming strategy for builders.
Have a look here in the documentation how to use Custom Accessor naming strategy.
Your mappings then need to look like:
#Mapper
public interface MyMapper {
default Immutable map(Source source) {
return mapToBuilder(source).build();
}
Immutable.Builder mapToBuilder(Source source);
}
Within MapStruct we are already working on a feature that would support out of the box support for builders. You can follow this issue for more details.
Update
MapStruct now (since 1.3.0.Beta1) has out of the box support for Immutables. This means that the mapper before can be written like:
#Mapper
public interface MyMapper {
Immutable map(Source source);
}
The assumption is that there is a public static method without parameters in Immutable that returns the builder
Uing Lombok and ModelMapper configure as:
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration()
.setFieldMatchingEnabled(true)
.setFieldAccessLevel(AccessLevel.PRIVATE);
By default ModelMapper uses only public setter method to map. When the class annotated with Lombok builder annotation it made the setter method as private. So to allow the ModelMapper to use the private setter method we need to add the above configureation.
OR
Configuration builderConfiguration = modelMapper.getConfiguration().copy()
.setDestinationNameTransformer(NameTransformers.builder())
.setDestinationNamingConvention(NamingConventions.builder());
modelMapper.createTypeMap(MyEntity.class, MyDto.MyDtoBuilder.class, builderConfiguration);
where MyEnity class is:
#Data
private static class MyEntity {
private Long id;
private String name;
private String value;
}
and builder class is:
#Data
#Builder
private static class MyDto {
private final Long id;
private final String name;
private final String value;
}
click here for detail

Java CDI inject non zero args constructor

I'm playing with java standard CDI and there is one concept I cannot get my head around. In the example below the Application class "requires" the Person class which cannot be injected since it has non-zero args constructor. How should I handle this scenario with CDI?
#Default
class Person {
private String name;
Person(String name) {
this.name=name;
}
String getName() {
return this.name;
}
}
class Application {
#Inject
public Application(Instance<Person> p)
}
There are three ways to inject objects without a no-args constructor. One is to use a producer to create the object.
#Produces
private Person producePerson() {
return new Person(name);
}
The second is to annotate one of the constructors with #Inject and make sure all of the parameters are valid injection targets.
class Person {
private String name;
#Inject
Person(String name) {
this.name=name;
}
String getName() {
return this.name;
}
}
and somewhere else:
#Produces
private String producePersonName() {
return name;
}
(Setting up multiple of these kinds of injections may require creating some qualifier annotations)
The third is to mess around with CDI container initialization with a custom extension, but that is overkill for such a relatively simple need.

Dynamic injection of collections into Spring managed beans

How can I inject a collection into a spring bean dynamically.
As I know
Example of my Author class
import java.util.List;
public class Author {
private String name;
private List<String> listOfBooks;
public Author(String name, List<String> listOfBooks) {
this.name = name;
this.listOfBooks = listOfBooks;
}
public Author() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getListOfBooks() {
return listOfBooks;
}
public void setListOfBooks(List<String> listOfBooks) {
this.listOfBooks = listOfBooks;
}
}
And my bean id is:
<bean id="authorID" class="com.test.Author">
</bean>
and some where I am using as #AutoWired bean for the Authors class.
And if I wants to add the books to the variable "listOfBooks".
How can I add it. is it by using reference to the Authors object and by accessing the getListOfBooks() method then adding the values. or is there any best way for this approach.
Thanks.
Some more detail explanation:
<property name="bookList">
<list>
<value>Java</value>
<value>C++</value>
</list>
</property>
This way we are Passing bean reference for java.util.List
Remember: To use above bean definition, you need to define your setter methods in such a way that they should be able to handle references as well.
ApplicationContext context =
new ClassPathXmlApplicationContext("YourBeans.xml");
Author a=(Author)context.getBean("authorID");
a.getListOfBooks();
Your Getter and Setter will be:
public void setListOfBooks(List<String> bookList) {
this.listOfBooks = bookList;
}
Also change getter accordingly.
Thank you
<property name="addressList">
<list>
<value>Book1</value>
<value>Book2</value>
<value>Book3</value>
<value>Book4</value>
</list>
</property>
In you context file.
For more information please see this post
Spring Injecting Collection here you can get an idea of injecting all types of collection [list,set,map] and array, and it's values as a primitive/reference

Persisting Full Data Binding POJO to Database

I have converted JSON response to POJO, following the concept of Full data binding.
POJO looks like this
public class User {
public Name _name;
#JsonCreator
public User(#JsonProperty("_name") Name _name,){
this._name=_name;
}
public static final class Name {
public String _first;
public Gender _gender;
#JsonCreator
public Name(#JsonProperty("_first") String _first,#JsonProperty("_gender") Gender _gender){
this._first = _first;
this._gender = _gender;
}
public static final class Gender {
public String age;
public Gender(#JsonProperty("age") String age){
this.age=age;
}
}
}
}
Now I need to persist this POJO, but I am not sure how should I do that efficiently, I have consider using Hibernate but I am unaware how to proceed.
How fields would be annotated in case I use Hibernate, since this is a complex POJO.
Is there a way I could use JDBC ? or any simpler and efficient way to achieve persistence with this kind of POJO.
Looking for a detail answer or an example or something that would clear my concept.
Thanks

How to store enum type as lowercase string?

My model class (piece):
public class User ... {
#Enumerated(STRING)
private Status status;
...
public enum Status {
ACTIVE,
INACTIVE;
#Override
public String toString() {
return this.name().toLowerCase();
}
}
...
public String getStatus() {
return status.name().toLowerCase();
}
public void setStatus(Status status) {
this.status = status;
}
}
As you see above I override toString method, but no effect.
Enumeration store in database as ACTIVE or INACTIVE.
P.S. I use hibernate jpa
Thanks for help!
P.S.S. I ask because I write REST service that produces json (in json object better use lower case, if I'm not mistake)
write a converter class, annotated with #Converter , which implements javax.persistence.AttributeConverter<YourEnum, String>. There are two methods:
public String convertToDatabaseColumn(YourEnum attribute){..}
public YourEnum convertToEntityAttribute(String dbData) {..}
there you can apply your upper/lower case logic.
Later you can annotated your field, for using the given converter.
Here's a quick and practical example of using AttributeConverter (introduced in JPA 2.1)
Update your enum class:
public enum Status {
ACTIVE,
INACTIVE;
public String toDbValue() {
return this.name().toLowerCase();
}
public static Status from(String status) {
// Note: error if null, error if not "ACTIVE" nor "INACTIVE"
return Status.valueOf(status.toUpperCase());
}
}
Create attribute converter:
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
#Converter(autoApply = true)
public class StatusConverter implements AttributeConverter<Status, String> {
#Override
public String convertToDatabaseColumn(Status status) {
return status.toDbValue();
}
#Override
public Status convertToEntityAttribute(String dbData) {
return Status.from(dbData);
}
}
If autoApply is set to true, you don't need to add the javax.persistence.Convert annotation to all attributes that shall be converted. Otherwise, apply the converter:
import javax.persistence.Convert;
import javax.persistence.Entity;
#Entity
public class User {
#Convert(converter = StatusConverter.class)
#Enumerated(STRING)
private Status status;
// ... other fields, constructor(s), standard accessors
}
If you're using Jackson for the REST service let Jackson do the conversion at the REST boundary. Your question doesn't state a requirement for the DB to store lower case or for the application to process lower case.
public enum Status {
STARTED,
CONSUMING,
GENERATING,
FAILED,
COMPLETED,
DELETED;
/**
* Serialises to and from lower case for jackson.
*
* #return lower case Status name.
*/
#JsonValue
public String toLower() {
return this.toString().toLowerCase(Locale.ENGLISH);
}
}
Best practice is to use the upper-case for enum constants.
I see two options
Use lower-case in enum (not a good practice)
Change the getter method (getStatus method) of the bean using this enum to return lower case. (best possible option)

Categories

Resources