Static access of Enums in Java? - java

I have two enums AttributesProperty and ResourceAttributesMapping each referencing each other as shown below:
import org.apache.commons.collections.map.HashedMap;
import test.xsd.Attribute;
public enum AttributesProperty {
ACP_RESOURCETYPE(ResourceAttributesMapping.ACCESSCONTROLPOLICY,"resourceType"),
ACP_RESOURCEID(ResourceAttributesMapping.ACCESSCONTROLPOLICY,"resourceID"),
.............
private ResourceAttributesMapping resource;
private String attributeName;
private AttributesProperty(ResourceAttributesMapping resource, String attributeName)
{
this.resource = resource;
this.attributeName = attributeName;
}
public static Map<ResourceAttributesMapping, List<Attribute>> getResTypeMapForAttrName(List<Attribute> attributesList) {
Map<ResourceAttributesMapping, List<Attribute>> attributeMap = new HashedMap();
List<Attribute> attrList = null;
List<ResourceAttributesMapping> resTypes = new ArrayList<ResourceAttributesMapping>();
for (Attribute attr : attributesList) {
boolean flag = false;
for (AttributesProperty attrProp : AttributesProperty.values()) {
if (attr.getName().equals(attrProp.getAttributeName())) {
if (attributeMap.get(attrProp.getResourceType()) == null) {
.........// Some logic
}
}
Referenced Enum: ResourceAttributesMapping.java
This enum as seen in imports statically importing the AttributesProperty enum.
import static xsd.enums.AttributesProperty.*;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections.map.HashedMap;
public enum ResourceAttributesMapping
{
ACCESSCONTROLPOLICY(1, Arrays.asList(ACP_RESOURCETYPE,ACP_RESOURCEID,............)),
AE(2, Arrays.asList(AE_RESOURCETYPE,AE_RESOURCEID,...........)),
....
private int resourceType;
private List<AttributesProperty> attrList;
private ResourceAttributesMapping(int resourceType, List<AttributesProperty> attrList) {
this.resourceType = resourceType;
this.attrList = attrList;
}
public int getM2MResourceTypes() {
return resourceType;
}
public List<AttributesProperty> getAttributeList(){
return attrList;
}
......// accessor methods
}
This code was running succesfully on JDK 8, WildFly 15 but after migrating to JDK 11 WildFly 20, I am getting a NullPointerException in the AttributesProperty 's enums accessor method:
public static Map<ResourceAttributesMapping, List<Attribute>> getResTypeMapForAttrName(List<Attribute> attributesList) {
Map<ResourceAttributesMapping, List<Attribute>> attributeMap = new HashedMap();
List<Attribute> attrList = null;
List<ResourceAttributesMapping> resTypes = new ArrayList<ResourceAttributesMapping>();
for (Attribute attr : attributesList) {
boolean flag = false;
for (AttributesProperty attrProp : AttributesProperty.values()) {
if (attr.getName().equals(attrProp.getAttributeName())) {
if (attributeMap.get(attrProp.getResourceType()) == null) {
.........// Some logic
attrProp.getResourceType() is giving null.
The test scenario is such that on first iteration of running the accesor methods in the enum it runs successfully, however on second iteration I get the NullPointerException.
Is there some change in Enums accessing from JDK 8 to 11?
Or the static access of second enum causing the issue.

Related

Java generic type validation

I have a generic super class which I'd like to validate:
abstract class Generic<T> {
// ... other validated fields
private T value;
}
Then I have several concrete classes and for each of it I'd like to appy specific validations on a value field.
E.g. for the below class I'd like to ensure that the value field is not less than 0.
class ConcreteInt<Integer> {
// #Min(0)
}
Another example, for the below class I'd like to ensure that the value is not blank.
class ConcreteString<String> {
// #NotBlank
}
Where should I put my validation annotations on a concrete classes to make them work?
I would suggest to use the Template design pattern and apply the validations accordingly.
First we have the generic class that accepts any type as T with an abstract method that the children must implement.
public abstract class Generic<T> {
protected T value;
abstract T getValue();
}
then we have a child for integer implementation with annotations #NotNull and #PositiveOrZero.
import javax.validation.constraints.NotNull;
import javax.validation.constraints.PositiveOrZero;
public class ConcreteInteger extends Generic<Integer> {
public ConcreteInteger(Integer v) {
value = v;
}
#Override
#NotNull
#PositiveOrZero
public Integer getValue() {
return value;
}
}
and a child for string implementation with annotations #NotNull, and #NotBlank. Here we already see that we can have different validations.
package com.yieldlab.reporting.dto.analytics;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
public class ConcreteString extends Generic<String> {
public ConcreteString(String v) {
value = v;
}
#Override
#NotNull
#NotBlank
public String getValue() {
return value;
}
}
But it won't validate if we just use the annotations. We have to invoke the javax.validation.Validator API. Here is one example:
import javax.validation.Configuration;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
public class BeanFieldValidationExample {
private static final Validator validator;
static {
Configuration<?> config = Validation.byDefaultProvider().configure();
ValidatorFactory factory = config.buildValidatorFactory();
validator = factory.getValidator();
factory.close();
}
public static void main(String[] args) {
// it won't validate by just call the constructor
ConcreteInteger concreteInteger0 = new ConcreteInteger(0);
System.out.println(concreteInteger0.value);
ConcreteInteger concreteInteger1 = new ConcreteInteger(1);
System.out.println(concreteInteger1.value);
ConcreteInteger concreteIntegerMinus1 = new ConcreteInteger(-1);
System.out.println(concreteIntegerMinus1.value);
ConcreteInteger concreteIntegerNull = new ConcreteInteger(null);
System.out.println(concreteIntegerNull.value);
ConcreteString concreteString0 = new ConcreteString("some string");
System.out.println(concreteString0.value);
ConcreteString concreteString1 = new ConcreteString("");
System.out.println(concreteString1.value);
ConcreteString concreteStringNull = new ConcreteString(null);
System.out.println(concreteStringNull.value);
// invoking the validator API will in validate our beans validator.validate(concreteInteger0).stream().forEach(BeanFieldValidationExample::printErrorConcreteInteger);
validator.validate(concreteInteger1).stream().forEach(BeanFieldValidationExample::printErrorConcreteInteger);
validator.validate(concreteIntegerMinus1).stream().forEach(BeanFieldValidationExample::printErrorConcreteInteger);
validator.validate(concreteIntegerNull).stream().forEach(BeanFieldValidationExample::printErrorConcreteInteger);
validator.validate(concreteString0).stream().forEach(BeanFieldValidationExample::printErrorConcreteString);
validator.validate(concreteString1).stream().forEach(BeanFieldValidationExample::printErrorConcreteString);
validator.validate(concreteStringNull).stream().forEach(BeanFieldValidationExample::printErrorConcreteString);
}
private static void printErrorConcreteInteger(ConstraintViolation<ConcreteInteger> concreteIntegerConstraintViolation) {
System.out.println(concreteIntegerConstraintViolation.getPropertyPath() + " " + concreteIntegerConstraintViolation.getMessage());
}
private static void printErrorConcreteString(ConstraintViolation<ConcreteString> concreteStringConstraintViolation) {
System.out.println(concreteStringConstraintViolation.getPropertyPath() + " " + concreteStringConstraintViolation.getMessage());
}
}
then we can see the output:
0
1
-1
null
some string
null
value must be greater than or equal to 0
value must not be null
value must not be blank
value must not be null
value must not be blank
I have found a solution. It's enough to override the getter of the class and place the annotations there:
class ConcreteString<String> {
#Override
#NotBlank
public String getValue(){
return super.getValue();
}
}

How to set & fetch fields of inner class in another class

package com.pr.trio;
import java.util.List;
public class lalala {
private List<SegmentationFieldValue> segmentationFieldValues;
public static class SegmentationFieldValue {
private Integer segmentationFieldId;
private Integer segmentationFieldGroupId;
private String value;
public Integer getSegmentationFieldId() {
return segmentationFieldId;
}
public void setSegmentationFieldId(Integer segmentationFieldId) {
this.segmentationFieldId = segmentationFieldId;
}
public Integer getSegmentationFieldGroupId() {
return segmentationFieldGroupId;
}
public void setSegmentationFieldGroupId(Integer segmentationFieldGroupId) {
this.segmentationFieldGroupId = segmentationFieldGroupId;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
public List<SegmentationFieldValue> getSegmentationFieldValues() {
return segmentationFieldValues;
}
public void setSegmentationFieldValues(List<SegmentationFieldValue> segmentationFieldValues) {
this.segmentationFieldValues = segmentationFieldValues;
}
}
package com.pr.trio;
import java.util.Arrays;
public class kk {
public static void main(String[] args) {
lalala l1 = new lalala();
//currently passed as an empty array, want to set SegmentationFieldId & value here from inner class
l1.setSegmentationFieldValues(Arrays.asList());
//lalala.SegmentationFieldValue.this.setSegmentationFieldId(15);
System.out.println(l1.getSegmentationFieldValues());
}
}
So here, I'm not able to pass values for the segmentation field instead of the empty array, gives an error. So how can I set the values from the inner class fields & pass it to my list?
Seeing as your SegmentationFieldValue class is public, it's trivial to use it inside another class, there are basically two ways to go about this:
The first is to import the inner class:
import com.pr.trio.lalala.SegmentationFieldValue;
The second is to qualify the classname whenever you use it:
lalala.SegmentationFieldValue a = new lalala.SegmentationFieldValue();
You can then call the setters on this class, and use the objects in your call to setSegmentationFieldValues:
lalala.SegmentationFieldValue a = new lalala.SegmentationFieldValue();
a.setSegmentationFieldId(1);
a.setSegmentationFieldGroupId(1);
a.setValue("a");
lalala.SegmentationFieldValue b = new lalala.SegmentationFieldValue();
b.setSegmentationFieldId(2);
b.setSegmentationFieldGroupId(1);
b.setValue("b");
l1.setSegmentationFieldValues(Arrays.asList(a, b));
Judging from your comment code, you also seem to be looking for a shorthand way to add an element to your list. A simple implementation could look like this (in class lalala):
public void addSegmentationFieldValue(Integer id, Integer groupId, String value)
{
if (segmentationFieldValues == null)
{
segmentationFieldValues = new ArrayList<>();
}
SegmentationFieldValue result = new SegmentationFieldValue();
result.setSegmentationFieldId(id);
result.setSegmentationFieldGroupId(groupId);
result.setValue(value);
segmentationFieldValues.add(result);
}
After which you can do the following in the main method of k1:
l1.addSegmentationFieldValue(1, 1, "a");

Java decoupling issue

am new to Java. I am trying to decouple the Responder class from the WeatherSystem Class. But I get an error at Public NewResponder in the Responder class (invalid method declaration; return type required), I am really stuck at this point. I have tried changing all the class points at NewResponder and responder but can't rectify it. Could anyone point out why I am getting this issue, please?
(I also have InputReader class but that's not included below).
WeatherSystem Class
import java.util.HashSet;
public class WeatherSystem
{
private InputReader reader;
private NewResponder responder;
public WeatherSystem(NewResponder responder)
{
reader = new InputReader();
this.responder = new Responder();
}
public void start()
{
boolean finished = false;
printWelcome();
while(!finished) {
HashSet<String> input = reader.getInput();
if(input.contains("exit")) {
finished = true;
}
else {
String response = this.responder.generateResponse(input);
System.out.println(response);
}
}
printGoodbye();
.............................................
Class Responder
import java.util.HashMap;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;
import WeatherSystem.NewResponder
public class Responder implements NewResponder
{
private HashMap<String, String> responseMap;
private ArrayList<String> defaultResponses;
private Random randomGenerator;
public NewResponder()
{
responseMap = new HashMap<>();
defaultResponses = new ArrayList<>();
fillResponseMap();
fillDefaultResponses();
randomGenerator = new Random();
}
public String generateResponse(HashSet<String> words)
{
for (String word : words) {
String response = this.responseMap.get(word);
if(response != null) {
return response;
}
}
return pickDefaultResponse();
....................................................
You really need to check whether you need interface NewResponder inside WeatherSystem. Which you are implementing in Responder class with wrong constructor name.

Morphia can't map List of List of Integer

I have a simplified example of a problem I am working on. I am trying to load a document that contains an array of an array of numbers.
{
"_id" : ObjectId("570cf0167640ed9f8bcff8e7"),
"matrix" : [
[
42
]
]
}
In order to create all indexes I call org.mongodb.morphia.Datastore#ensureIndexes(). As I understand, from what is documented, I need to call org.mongodb.morphia.Morphia#map(Class ...) to tell Morphia on which classes to look for #Indexes annotation. Without Morphia#map(...) the app runs fine (and as expected no indexes will be created). If I add Morphia#map(...) I get an Exception.
Exception in thread "main" java.lang.RuntimeException: java.lang.IllegalArgumentException: BasicBSONList can only work with numeric keys, not: [elementData]
at org.mongodb.morphia.mapping.EmbeddedMapper.fromDBObject(EmbeddedMapper.java:74)
at org.mongodb.morphia.mapping.Mapper.readMappedField(Mapper.java:772)
at org.mongodb.morphia.mapping.Mapper.fromDb(Mapper.java:230)
at org.mongodb.morphia.mapping.Mapper.fromDBObject(Mapper.java:191)
at org.mongodb.morphia.query.MorphiaIterator.convertItem(MorphiaIterator.java:134)
at org.mongodb.morphia.query.MorphiaIterator.processItem(MorphiaIterator.java:146)
at org.mongodb.morphia.query.MorphiaIterator.next(MorphiaIterator.java:117)
at org.mongodb.morphia.query.QueryImpl.asList(QueryImpl.java:150)
at it.test.Main.fails(Main.java:41)
at it.test.Main.main(Main.java:24)
Caused by: java.lang.IllegalArgumentException: BasicBSONList can only work with numeric keys, not: [elementData]
at org.bson.types.BasicBSONList._getInt(BasicBSONList.java:168)
at org.bson.types.BasicBSONList._getInt(BasicBSONList.java:160)
at org.bson.types.BasicBSONList.get(BasicBSONList.java:105)
at org.mongodb.morphia.mapping.MappedField.getDbObjectValue(MappedField.java:190)
at org.mongodb.morphia.converters.Converters.fromDBObject(Converters.java:121)
at org.mongodb.morphia.mapping.ValueMapper.fromDBObject(ValueMapper.java:20)
at org.mongodb.morphia.mapping.Mapper.readMappedField(Mapper.java:766)
at org.mongodb.morphia.mapping.Mapper.fromDb(Mapper.java:230)
at org.mongodb.morphia.mapping.EmbeddedMapper.readMapOrCollectionOrEntity(EmbeddedMapper.java:206)
at org.mongodb.morphia.mapping.EmbeddedMapper.readCollection(EmbeddedMapper.java:142)
at org.mongodb.morphia.mapping.EmbeddedMapper.fromDBObject(EmbeddedMapper.java:45)
... 9 more
Can someone explain why explicitly calling map() breaks Morphia?
The following exmaple reproduces the problem (just add org.mongodb.morphia:morphia:1.1.1 as dependency).
package it.test;
import java.util.List;
import org.bson.types.ObjectId;
import org.mongodb.morphia.Datastore;
import org.mongodb.morphia.Morphia;
import org.mongodb.morphia.dao.BasicDAO;
import org.mongodb.morphia.query.QueryResults;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import it.test.model.Doc;
public class Main {
private static final String URI = "mongodb://localhost:27017";
private static final String NAME = "test";
private static final MongoClientURI CLIENT_URI = new MongoClientURI(URI + "/" + NAME);
public static void main(String[] args) {
Main main = new Main();
main.works();
main.fails();
}
private void fails() {
try (MongoClient client = new MongoClient(CLIENT_URI)) {
Morphia morphia = new Morphia();
morphia.getMapper().getOptions().setStoreEmpties(true);
morphia.mapPackage("it.test.model");
find(morphia, client, CLIENT_URI.getDatabase());
}
}
private void works() {
try (MongoClient client = new MongoClient(CLIENT_URI)) {
Morphia morphia = new Morphia();
morphia.getMapper().getOptions().setStoreEmpties(true);
// morphia.mapPackage("it.test.model"); // bad call?
find(morphia, client, CLIENT_URI.getDatabase());
}
}
private void find(Morphia morphia, MongoClient client, String dbName) {
Datastore datastore = morphia.createDatastore(client, dbName);
BasicDAO<Doc, ObjectId> dao = new BasicDAO<>(Doc.class, datastore);
QueryResults<Doc> result = dao.find();
List<Doc> rootEntities = result.asList();
System.out.println("Found " + rootEntities.size() + " RootEntity documents.");
}
}
package it.test.model;
import java.util.List;
import org.bson.types.ObjectId;
import org.mongodb.morphia.annotations.Entity;
import org.mongodb.morphia.annotations.Id;
#Entity
public class Doc {
#Id
private ObjectId id;
public ObjectId getId() {
return id;
}
public void setId(ObjectId id) {
this.id = id;
}
private List<List<Integer>> matrix;
public List<List<Integer>> getMatrix() {
return matrix;
}
public void setMatrix(List<List<Integer>> matrix) {
this.matrix = matrix;
}
}
If you look at this test you can see List<List<Integer>> works just fine. Looking at your example, I don't see anything obvious that would lead to the errors you're getting but I can verify at least that List<List<Integer>> works. What version of the Java driver are you using? It should be in the 3.x line at the least.

JAX-RS / JAXB : equals()

I'm creating a little webservice with JAX-RS and I cannot access to my GET request http://localhost:8080/MyProject/resources/agenda/{jour}
Here is my code :
package com.project.test;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.List;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.PathParam;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.xml.bind.annotation.*;
#XmlRootElement(name = "activite")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(propOrder = {"but","trancheHoraire", "lieu"})
public class Activite
{
//-----------------------------------------------------------------------------
// #XmlElement(name="nomactivite")
private String but;
private TrancheHoraire trancheHoraire;
private String lieu;
//-----------------------------------------------------------------------------
public Activite(){
}
public Activite(String but,TrancheHoraire trancheHoraire, String lieu)
{
this.but = but;
this.trancheHoraire = trancheHoraire;
this.lieu = lieu;
}
//-----------------------------------------------------------------------------
public String getBut() { return but; }
public TrancheHoraire getTrancheHoraire() {
return trancheHoraire;
}
public String getLieu() { return lieu; }
public void setBut(String but) {
this.but = but;
}
public void setTrancheHoraire(TrancheHoraire trancheHoraire) {
this.trancheHoraire = trancheHoraire;
}
public void setLieu(String lieu) {
this.lieu = lieu;
}
public Date getDate (){
return this.getTrancheHoraire().getDate();
}
}
TrancheHoraire class :
package com.project.test;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
//#XmlType(name = "trancheHoraire", propOrder = {"date", "part_journee"})
public class TrancheHoraire
{
//-----------------------------------------------------------------------------
// #XmlElement(required = true)
private Date date;
// #XmlElement(required = true)
private int part_journee;
public String part_journee_v;
//-----------------------------------------------------------------------------
public TrancheHoraire(){
}
public TrancheHoraire(Date date, int part_journee)
{
this.date = date;
this.part_journee = part_journee;
}
//-----------------------------------------------------------------------------
public Date getDate() { return date; }
public int getpart_journee()
{
return part_journee;
}
}
My Database :
package com.project.test;
import java.util.ArrayList;
import java.util.List;
public class ActiviteBD {
private static List<Activite> activites = new ArrayList<Activite>();
static {
activites.add(new Activite("RĂ©union", new TrancheHoraire(new Date(01, 10, 2015), 2), "Paris"));
activites.add(new Activite("Vacances", new TrancheHoraire(new Date(02, 10, 2015), 2), "Marseille"));
activites.add(new Activite("Resto", new TrancheHoraire(new Date(03, 10, 2015), 2), "Lyon"));
}
public static List<Activite> getActivites() {
return activites;
}
}
And I call webservices with this class :
package com.project.test;
import java.util.List;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
/**
*
* #author rcaboni
*/
#Path("/agenda")
public class Resource
{
#GET
#Produces("application/xml")
public List<Activite> getActivites() {
return ActiviteBD.getActivites();
}
#GET
#Path("{jour}")
#Produces("application/xml")
public Activite getActiviteByDate(#PathParam("jour") int jour){
System.out.println("getActivite");
Activite tranche = new Activite("RĂ©union", new TrancheHoraire(new Date(jour, 10, 2015), 2), "Marseille");
TrancheHoraire th = tranche.getTrancheHoraire();
System.out.println(tranche.getDate());
for (Activite _current : ActiviteBD.getActivites()) {
System.out.println(_current.getTrancheHoraire());
if (th.equals(_current.getTrancheHoraire())) {
System.out.println(_current.getTrancheHoraire());
return _current;
}
}
return null;
}
}
If I call /agenda, it returns all my activities.
Like this :
However, if I call /agenda/1 , it should return my first activitie...
In my console : getTrancheHoraire returns something like this : com.project.test.TrancheHoraire#75a630fb
I've read plugin on Equals() class is the only one solution.
Could you help me ? :)
"I've read plugin on Equals() class is the only one solution."
I guess "plugin on" means override. If not, then that's you it should mean. You need to override it, and describe how the objects will be determined equal. (It should also be noted, when override equals, you should also override hashcode).
See when should I override Equals function?
That being said, most IDEs, will be able to generate this for you. For example, with Netbeans, I just right click the class, select "Insert Code" and select equals() and hashcode(). Then select the properties I want to include in the comparison. I selected all, and got this
#Override
public int hashCode() {
int hash = 5;
hash = 79 * hash + Objects.hashCode(this.date);
hash = 79 * hash + this.part_journee;
hash = 79 * hash + Objects.hashCode(this.part_journee_v);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final TrancheHoraire other = (TrancheHoraire) obj;
if (!Objects.equals(this.date, other.date)) {
return false;
}
if (this.part_journee != other.part_journee) {
return false;
}
if (!Objects.equals(this.part_journee_v, other.part_journee_v)) {
return false;
}
return true;
}
I know Eclipse has similar feature.
As an aside, your comparison looks kind of odd. Why do you need to create a new Activite? The method is getActiviteByDate, so why don't you just look for Activites with the date.
Try adding a / before your {jour} declaration in the #Path annotation, like so:
#Path("/{jour}")
The mapping you've got currently looks like it may be routing requests to /agenda1.

Categories

Resources