I have the following inheritance hierarchy defined in java.
public class BaseModel extends HashMap<String, Object> {
public String getString(String key) {
return (String)this.getOrDefault(key, "EMPTY");
}
}
public class Entity extends BaseModel {
private String id;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
Now in a groovy script I try to do the following:
Entity entity = new Entity();
entity.id = "101";
entity.name = "Apple"
and "id" and "name" are not recognized. The funny thing is they are recognized if I do one of the following:
not inherit Entity from BaseModel
Rather than inherit BaseModel from HashMap, make HashMap a data member of BaseModel
inherit Entity directly from HashMap
At first I thought that groovy is not recognizing the "id" and "name" syntax because of extending HashMap, but #3 above proves that incorrect. I am stumped as to why this is not being recognized at this point. Can someone help me out? It should be easy enough to copy paste this and try it out yourself.
The problem seems to be the setters and getters inside the Entity Class, everything in groovy is public and it creates all the getters and setters methods.
I tested the next code in the groovy console and it worked.
public class BaseModel extends HashMap<String, Object> {
public String getString(String key) {
return (String)this.getOrDefault(key, "EMPTY");
}
}
public class Entity extends BaseModel {
private String id;
private String name;
}
Entity entity = new Entity();
entity.id = "101";
entity.name = "Apple"
println entity.id
It prints 101 in the groovyConsole output screen.
When Entity is extending from BaseModel or directly a HashMap, Entity becomes a Map. So, when we say entity.id, Groovy is trying to find an entry in the map whose key is 'id'. As there is no such entry, it prints out null.
public class Entity extends HashMap<String, String> {
private String id;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
Entity entity = new Entity();
entity.id = "101";
entity.name = "Apple"
println entity.id //prints null
But when Entity is not extending from BaseModel anymore, entity.id will be interpreted just as a member of Entity.
public class Entity {
private String id;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
Entity entity = new Entity();
entity.id = "101";
entity.name = "Apple"
println entity.id //prints 101
Related
I am trying to create my custom configuration object from Map using model mapper. Everything gets mapped properly excepts the fields property which is coming fro Generic super class.
My target object is
public class ADParserConfig extends CustomParserConfig<ADParserConfigField> {
private String pattern;
public String getPattern() {
return pattern;
}
public void setPattern(String pattern) {
this.pattern = pattern;
}
}
This extends generic class CustomParserConfig
public class CustomParserConfig<T extends CustomParserConfigField> {
protected List<T> fields;
protected String timeStampField;
public List<T> getFields() {
return fields;
}
public void setFields(List<T> fields) {
this.fields = fields;
}
public String getTimeStampField() {
return timeStampField;
}
public void setTimeStampField(String timeStampField) {
this.timeStampField = timeStampField;
}
}
Where CustomParserConfigField is
public class CustomParserConfigField {
protected String name;
protected Integer index;
protected String type;
protected String format;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getIndex() {
return index;
}
public void setIndex(Integer index) {
this.index = index;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
}
I am trying to map Map using below function
ADParserConfig adParserConfig = getConfig(map,ADParserConfig.class);
public <T extends CustomParserConfig> T getConfig(Map<String,Object> configObject, Class<T> classType){
ModelMapper modelMapper = new ModelMapper();
return modelMapper.map(configObject,classType);
}
Everything excepts fields gets mapped properly for the below map.
{fields=[{name=timeStamp, type=timestamp, format=dd/mm/yyyy HH:MM:SS a}, {name=logName, type=string}], pattern=(?<timeStamp>\d{2}\/\d{2}\/\d{4}\s\d{2}:\d{2}:\d{2}\s[AMPMampm]{2})?\s(LogName=(?<logName>[\w\s\W]+))?\sSourceName=(?<sourceName>[\w\s\W]+)\sEventCode=(?<eventCode>[0-9]*), timeStampField=timestamp}
Please help. Why is issue happens only for fields object ? Do I need to specify something else in mapper configurations ?
It looks like a bug and it had been fixed by #370
I managed to create very simple example of sending Object between JSF pages:
First page:
#Named
#ViewScoped
public class Pricing
{
public Pricing()
{
int ww = 3;
PricingFormData obj = new PricingFormData(334, "Lalalala");
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("yourKey", obj);
}
Second page:
#Named
#ViewScoped
public class PricingCalculator implements Serializable
{
PricingFormData get;
public PricingCalculator()
{
get = (PricingFormData) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("yourKey");
}
}
Custom Object:
public class PricingFormData
{
private int id;
private String name;
public PricingFormData(int id, String name)
{
this.id = id;
this.name = name;
}
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
This code works but I have several questions which I want to ask:
The code is working in View scope. What will happen if multiple users are clicking on the pages? Are these Objects are going to be mixed? Do I need to use some unique ID for Object key for example session ID. But here I don't have session.
What will happen if the Objects are too many(multiple users are working on the web site)? When the objects will be disposed?
I'm trying to use spring-data-cassandra (1.1.2.RELEASE) and I'm running into an issue with the lack of embeddable type mapping in JPA parlance.
I have an entity class like this:
#Table
public class Customer {
private UUID id;
private String name;
private Address address;
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
and the embeddable Address class:
public class Address {
private String address;
private String city;
private String state;
private String zip;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getZip() {
return zip;
}
public void setZip(String zip) {
this.zip = zip;
}
}
My cassandra table:
create table customer (
id uuid primary key,
name text,
address text,
city text,
state text,
zip text
);
I want the properties of Address to be mapped into the containing entity, I don't want a separate table for addresses. In JPA, I believe I'd use an #Embeddable annotation. Is there some similar construct in spring-data-cassandra?
Embeddable types are not yet supported by spring-data-cassandra. A feature request is available at DATACASS-167.
The only possible part of an entity to embed is the primary key. If your primary key consists of multiple fields, you can externalize that fields into a separate class and use it afterwards with the #PrimaryKey annotation.
Comment.java
#Table("comments")
public class Comment {
#PrimaryKey
private CommentKey pk;
private String text;
}
CommentKey.java
#PrimaryKeyClass
public class CommentKey implements Serializable {
private static final long serialVersionUID = -7871651389236401141L;
#PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED)
private String author;
#PrimaryKeyColumn(ordinal = 1)
private String company;
}
HTH, Mark
Here I got two classes "Student" and "Course":
#XmlRootElement
class Student {
private String name;
private HashMap<String, Course> courses;
public Student() {}
public Student(String name, HashMap<String, Course> courses) {
super();
this.name = name;
this.courses = courses;
}
// -------------------------getters
#XmlAttribute(name="name")
public String getName() {
return name;
}
#XmlElement(name = "course")
public HashMap<String, Course> getCourses() {
return courses;
}
//---------------------------setters
public void setName(String name) {
this.name = name;
}
public void setCourses(HashMap<String, Course> courses) {
this.courses = courses;
}
}
#XmlRootElement
class Course {
private String id;
private String name;
public Course() {}
public Course(String id, String name) {
super();
this.id = id;
this.name = name;
}
#XmlID
#XmlAttribute(name = "id")
public String getId() {
return id;
}
#XmlAttribute(name = "name")
public String getName() {
return name;
}
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
}
I want to serialize the Student class using JaxB annotations to something like the following:
<Student name="David">
<courses>
<Course id="1" name="Fundamentals of Programming"/>
<Course id="2" name="Advanced Programming">
</courses>
</Student>
Note that I want courses field of the Student to be HashMap and when unmarshalling the serialized Object use id as the key for each Course.
You can use an XmlAdapter for this use case. An XmlAdapter allows you to programmatically convert an object to another type for the purpose of marshalling/unmarshalling. For your use case you will convert the HashMap to an instance of an object that has a collection of Course.
http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html
Here is what I have so far to marshall my POJO using JAXB :
#XmlRootElement
public class Local {
private Entity entity;
public void setEntity(Entity entity) {
this.entity = entity;
}
#XmlElement
public Entity getEntity() {
return entity;
}
}
and
#XmlRootElement
public class Entity {
private String name;
private String comment;
public void setName(String name){
this.name = name;
}
#XmlAttribute
public String getName(){
return this.name;
}
public void setComment...
#XmlAttribute
public void getComment...
}
With that, I get something like this:
<local>
<entity name="" comment=""></entity>
</local>
However, I would prefer to have the name attribute as an attribute of the local:
<local entityName="" entityComment=""></local>
Is the XmlJavaTypeAdapter a good way to begin with?
Thanks,
Alex
There are a couple of different options to handle this use case:
Option #1 - XmlAdapter (Any JAXB implementation)
You could use an XmlAdapter for this use case. This will work as long as only one attribute value comes from the Entity object:
EntityAdapter
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class EntityAdapter extends XmlAdapter<String, Entity>{
#Override
public String marshal(Entity entity) throws Exception {
if(null == entity) {
return null;
}
return entity.getName();
}
#Override
public Entity unmarshal(String name) throws Exception {
Entity entity = new Entity();
entity.setName(name);
return entity;
}
}
Local
The XmlAdapter is linked with the field/property using the #XmlJavaTypeAdapter annotation:
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#XmlRootElement
public class Local {
private Entity entity;
public void setEntity(Entity entity) {
this.entity = entity;
}
#XmlAttribute
#XmlJavaTypeAdapter(EntityAdapter.class)
public Entity getEntity() {
return entity;
}
}
For More Information
http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html
http://blog.bdoughan.com/2010/12/jaxb-and-immutable-objects.html
Option #2 - #XmlPath (EclipseLink JAXB (MOXy)
Alternatively if you are using EclipseLink JAXB (MOXy), the you could use the #XmlPath extension. This is useful with the Entity object corresponds to multiple XML attributes:
Local
Specifying the XPath "." indicated that the child contents will be written into the parent element
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.*;
#XmlRootElement
public class Local {
private Entity entity;
public void setEntity(Entity entity) {
this.entity = entity;
}
#XmlPath(".")
public Entity getEntity() {
return entity;
}
}
Entity
public class Entity {
private String name;
private String comment;
public void setName(String name){
this.name = name;
}
#XmlAttribute(name="entityName")
public String getName(){
return this.name;
}
public void setComment(String comment){
this.comment = comment;
}
#XmlAttribute(name="entityComment")
public String getComment(){
return this.comment;
}
}
For More Information
http://bdoughan.blogspot.com/2010/07/xpath-based-mapping.html
http://blog.bdoughan.com/2010/09/xpath-based-mapping-geocode-example.html
http://blog.bdoughan.com/2011/03/map-to-element-based-on-attribute-value.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html