With Jaxb (jaxb-impl-2.1.12), UI try to read an XML file
Only a few element in the XML file are interesting, so I would like to skip most of the elements.
The XML I'm trying to read:
<?xml version="1.0" encoding="UTF-8"?>
<!--Sample XML file generated by XMLSpy v2010 rel. 3 sp1 (http://www.altova.com)-->
<flx:ModeleREP xsi:schemaLocation="urn:test:mod_rep.xsd mod_rep.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:flx="urn:test:mod_rep.xsd">
<flx:DocumentHeader>
<flx:Identification v="04489"/>
</flx:DocumentHeader>
<flx:TimeSeries>
<flx:Identification v="test1a"/>
<flx:BusinessType v="A01"/>
<flx:Product v="123a"/>
<flx:ResourceObject codingScheme="N" v="testa"/>
<flx:Period>
<flx:TimeInterval v="2011-07-02T00:00/2011-07-16T00:00"/>
<flx:Resolution v="PT2H"/>
<flx:Pt>
<flx:P v="1"/>
<flx:Q unitCode="String" v="1.0"/>
<flx:A currencyIdentifier="String" v="195.0"/>
</flx:Pt>
</flx:Period>
</flx:TimeSeries>
<flx:TimeSeries>
<flx:Identification v="test2a"/>
<flx:BusinessType v="A01"/>
<flx:Product v="a123b"/>
<flx:ResourceObject codingScheme="N" v="test2"/>
<flx:Period>
<flx:TimeInterval v="2011-07-02T00:00/2011-07-16T00:00"/>
<flx:Resolution v="PT2H"/>
<flx:Pt>
<flx:P v="1"/>
<flx:Q unitCode="String" v="1.0"/>
<flx:A currencyIdentifier="String" v="195.0"/>
</flx:Pt>
<flx:Pt>
<flx:P v="2"/>
<flx:Q unitCode="String" v="1.0"/>
<flx:A currencyIdentifier="String" v="195.0"/>
</flx:Pt>
</flx:Period>
</flx:TimeSeries>
</flx:ModeleREP>
my class
#XmlRootElement(name="ModeleREP", namespace="urn:test:mod_rep.xsd")
public class ModeleREP {
#XmlElement(name="TimeSeries")
protected List<TimeSeries> timeSeries;
public List<TimeSeries> getTimeSeries() {
if (this.timeSeries == null) {
this.timeSeries = new ArrayList<TimeSeries>();
}
return this.timeSeries;
}
public void setTimeSeries(List<TimeSeries> timeSeries) {
this.timeSeries = timeSeries;
}
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "TimeSeries")
public class TimeSeries {
#XmlElement(name="ResourceObject")
protected RessourceObject resourceObject;
#XmlElement(name = "Period")
protected Period period;
public RessourceObject getResourceObject() {
return this.resourceObject;
}
public void setResourceObject(RessourceObject resourceObject) {
this.resourceObject = resourceObject;
}
public Period getPeriod() {
return this.period;
}
public void setPeriod(Period period) {
this.period = period;
}
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "ResourceObject")
public class RessourceObject {
#XmlAttribute(name = "codingScheme")
protected String codingScheme;
#XmlAttribute(name = "v")
protected String v;
public String getCodingScheme() {
return this.codingScheme;
}
public void setCodingScheme(String codingScheme) {
this.codingScheme = codingScheme;
}
public String getV() {
return this.v;
}
public void setV(String v) {
this.v = v;
}
}
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name = "Period")
public class Period {
#XmlElement(name = "TimeInterval")
protected TimeInterval timeInterval;
#XmlElement(name = "Pt")
protected List<Pt> pt;
public TimeInterval getTimeInterval() {
return this.timeInterval;
}
public void setTimeInterval(TimeInterval timeInterval) {
this.timeInterval = timeInterval;
}
public List<Pt> getPt() {
if (this.pt == null) {
this.pt = new ArrayList<Pt>();
}
return this.pt;
}
public void setPt(List<Pt> pt) {
this.pt=pt;
}
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "TimeInterval")
public class TimeInterval {
#XmlAttribute(name = "v")
private String timeIntervalPeriod;
public String getTimeIntervalPeriod() {
return this.timeIntervalPeriod;
}
public void setTimeIntervalPeriod(String timeIntervalPeriod) {
this.timeIntervalPeriod = timeIntervalPeriod;
}
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "Pt")
public class Pt {
#XmlElement(name = "P")
protected P p;
#XmlElement(name = "A")
protected A a;
public P getP() {
return this.p;
}
public void setP(P p) {
this.p = p;
}
public A getA() {
return this.a;
}
public void setA(A a) {
this.a = a;
}
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "P")
public class P {
#XmlAttribute(name = "v")
protected String position;
public String getPosition(){
return this.position;
}
public void setPosition(String position){
this.position=position;
}
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "A")
public class A {
#XmlAttribute(name = "v")
protected String calculatedAmount;
public String getCalculatedAmount() {
return this.calculatedAmount;
}
public void setCalculatedAmount(String calculatedAmount) {
this.calculatedAmount = calculatedAmount;
}
}
when I try to read the XML file, I get this error:
com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Class has two properties of the same name "timeSeries"
this problem is related to the following location:
at public java.util.List testjaxp.ModeleREP.getTimeSeries()
at testjaxp.ModeleREP
this problem is related to the following location:
at protected java.util.List testjaxp.ModeleREP.timeSeries
at testjaxp.ModeleREP
I don't understand this error. And sometimes when I check my object, timeSeries is null.
How can I fix this error/prevent timeSeries from returning null?
I set these properties when I faced this problem. Setting one or both of them may solve your issue:
#XmlRootElement(name="yourRootElementName")
#XmlAccessorType(XmlAccessType.FIELD)
There are multiple solutions: If you annotate on variable declaration then you need #XmlAccessorType(XmlAccessType.FIELD), but if you prefer to annotate either a get- or set-method then you don't.
So you can do:
#XmlRootElement(name="MY_CLASS_A")
#XmlAccessorType(XmlAccessType.FIELD)
public class MyClassA
{
#XmlElement(name = "STATUS")
private int status;
//.. and so on
}
Or:
#XmlRootElement(name="MY_CLASS_A")
public class MyClassA
{
private int status;
#XmlElement(name = "STATUS")
public int getStatus()
{
}
}
You didn't specified what JAXB-IMPL version are you using, but once I had the same problem (with jaxb-impl 2.0.5) and solved it using the annotation at the getter level instead of using it at the member level.
I've also seen some similiar issues like this.
I think, it's because of the place where we use the "#XMLElement" annotation in the (bean) class.
And I think, the JAXB (annotation processor) considers the member field & getter method of the same field element as different properties, when we use the #XMLElement annotation at the field level and throws the IllegalAnnotationExceptions exception.
Exception Message :
Class has two properties of the same name "timeSeries"
At Getter Method :
at public java.util.List testjaxp.ModeleREP.getTimeSeries()
At Member Field :
at protected java.util.List testjaxp.ModeleREP.timeSeries
Solution :
Instead of using #XmlElement in the field, use it in the getter method.
just added this to my class
#XmlAccessorType(XmlAccessType.FIELD)
worked like a cham
Your JAXB is looking at both the getTimeSeries() method and the member timeSeries. You don't say which JAXB implementation you're using, or its configuration, but the exception is fairly clear.
at public java.util.List testjaxp.ModeleREP.getTimeSeries()
and
at protected java.util.List testjaxp.ModeleREP.timeSeries
You need to configure you JAXB stuff to use annotations (as per your #XmlElement(name="TimeSeries")) and ignore public methods.
If we use the below annotations and remove the "#XmlElement" annotation, code should work properly and resultant XML would have the element names similar to the class member.
#XmlRootElement(name="<RootElementName>")
#XmlAccessorType(XmlAccessType.FIELD)
In case use of "#XmlElement" is really required, please define it as field level and code should work perfectly. Don't define the annotation on the top of getter method.
Had tried both the above approaches mentioned and got to fix the issue.
You need to configure class ModeleREP as well with #XmlAccessorType(XmlAccessType.FIELD) as you did with class TimeSeries.
Have al look at OOXS
"Class has two properties of the same name exception" can happen when you have a class member x with a public access level and a getter/setter for the same member.
As a java rule of thumb, it is not recommended to use a public access level together with getters and setters.
Check this for more details:
Public property VS Private property with getter?
To fix that:
Change your member's access level to private and keep your getter/setter
Remove the member's getter and setter
These are the two properties JAXB is looking at.
public java.util.List testjaxp.ModeleREP.getTimeSeries()
and
protected java.util.List testjaxp.ModeleREP.timeSeries
This can be avoided by using JAXB annotation at get method just like mentioned below.
#XmlElement(name="TimeSeries"))
public java.util.List testjaxp.ModeleREP.getTimeSeries()
Declare the member variables to private in the class you want to convert to XML.
It will work when you put your annotation before the getters, and remove it from the protected attributes:
protected String codingScheme;
#XmlAttribute(name = "codingScheme")
public String getCodingScheme() {
return this.codingScheme;
}
The source of the problem is that you have both XmlAccessType.FIELD and pairs of getters and setters. The solution is to remove setters and add a default constructor and a constructor that takes all fields.
ModeleREP#getTimeSeries() have to be with #Transient annotation. That would help.
I had a service class with a signature as below:
#WebMethod
public FetchIQAStatusResponseVO fetchIQAStatus(FetchIQAStatusRequest fetchIQAStatusRequest) {
On run I got the same error for FetchIQAStatusResponseVO fields. I just added a line on top of FetchIQAStatusResponseVO:
#XmlAccessorType(XmlAccessType.FIELD) //This line added
public class FetchIQAStatusResponseVO {
and this resolved the issue.
Annotating with #XmlTransient resolves that issue
#XmlTransient
public void setTimeSeries(List<TimeSeries> timeSeries) {
this.timeSeries = timeSeries;
}
Look at http://docs.oracle.com/javase/8/docs/api/javax/xml/bind/annotation/XmlTransient.html for more details
Many solutions have been given, and the internals are briefly touched by #Sriram and #ptomli as well. I just want to add a few references to the source code to help understand what is happening under the hood.
By default (i.e. no extra annotations used at all except #XmlRootElement on the root class), JABX tries to marshal things exposed via two ways:
public fields
getter methods that are named following the convention and have a corresponding setter method.
Notice that if a field is (or method returns) null, it will not be written into the output.
Now if #XmlElement is used, non-public things (could be fields or getter methods) can be marshalled as well.
But the two ways, i.e. fields and getter-methods, must not conflict with each other. Otherwise you get the exception.
A quick and simple way to fix this issue is to remove the #XmlElement(name="TimeSeries") from the top of the variable declaration statement protected List<TimeSeries> timeSeries; to the top of its getter, public List<TimeSeries> getTimeSeries().
Thus your ModeleREP class will look like:
#XmlRootElement(name="ModeleREP", namespace="urn:test:mod_rep.xsd")
public class ModeleREP {
protected List<TimeSeries> timeSeries;
#XmlElement(name="TimeSeries")
public List<TimeSeries> getTimeSeries() {
if (this.timeSeries == null) {
this.timeSeries = new ArrayList<TimeSeries>();
}
return this.timeSeries;
}
public void setTimeSeries(List<TimeSeries> timeSeries) {
this.timeSeries = timeSeries;
}
}
I did trial and error and got the conclusion that, you only have to use either of both #XMLElement or #XmlAccessorType(XmlAccessType.FIELD).
When to use which?
case 1 : If your field names and element name you want to use in xml file are different then you have to use #XMLElement(name="elementName"). As this will bind fields with that element name and display in XML file.
case 2 : If fields names and respective element name in xml both are same then you can simply use #XmlAccessorType(XmlAccessType.FIELD)
Related
Getting both java obejct as will jsonproperty is getting generated whilc I convert java object to JSON.
Can you please confirm where I have made mistake.
Add #JsonAutoDetect(getterVisibility= JsonAutoDetect.Visibility.NONE) to your class:
#JsonAutoDetect(getterVisibility= JsonAutoDetect.Visibility.NONE)
#JsonInclude(JsonInclude.Include.NON_EMPTY)
public class FalconidePersonalizationVO {
By default Jackson follow java bean convention to output json properties. As result, it founds your getX method and output xapiheader property.
But you also annotate your field with #JsonProperty so another property named x-apiheader is also ouputed.
Disable getterX detection method will prevent jackson output getter fields.
**************** Solution 1 ****************
Annotate getter / setter with #JsonProperty as well (now annotating field is not mandatory)
public class FalconidePersonalizationVO {
#JsonProperty("x-apiheader-cc")
private String xApiheaderCc;
#JsonProperty("x-apiheader")
private String xApiheader;
#JsonProperty("x-apiheader-cc")
public String getXApiheaderCc() {
return xApiheaderCc;
}
#JsonProperty("x-apiheader-cc")
public void setXApiheaderCc(String xApiheaderCc) {
this.xApiheaderCc = xApiheaderCc;
}
#JsonProperty("x-apiheader")
public String getXApiheader() {
return xApiheader;
}
#JsonProperty("x-apiheader")
public void setXApiheader(String xApiheader) {
this.xApiheader = xApiheader;
}
}
**************** Solution 2 ****************
Follow setter / getter naming convention. In normal naming convention first letter of field name is capitalized prepending it with set / get. But in this case since second char is capital so, first char is not capitalized. See https://stackoverflow.com/a/16146215/3295987
public class FalconidePersonalizationVO {
#JsonProperty("x-apiheader-cc")
private String xApiheaderCc;
#JsonProperty("x-apiheader")
private String xApiheader;
/*
* Setter / getter auto generated in eclipse
*/
// getXApiheaderCc -> getxApiheaderCc
public String getxApiheaderCc() {
return xApiheaderCc;
}
public void setxApiheaderCc(String xApiheaderCc) {
this.xApiheaderCc = xApiheaderCc;
}
public String getxApiheader() {
return xApiheader;
}
public void setxApiheader(String xApiheader) {
this.xApiheader = xApiheader;
}
}
Trying to extend the below linked Sonarqube rule to ignore the occurrence of a string literal in a logger method.
I am having issues trying to extract method names for methods (which in the context of the Base Visitor Tree may not be scoped as methods from my analysis. But have had some luck looking at methodInvocation type to extract a few method names).
So my question is does any one have a definition list of the Base Visitor Tree elements and how it would see different statements?
e.g. weeLogger.Log(exception, "exception occurred");
or
e.g. logger(exception1, "exception occured);
And as well has anyone done anything similar and share how they extracted out method names from the Base Visitor Tree class for analysis with Sonarqube?
https://github.com/SonarSource/sonar-java/blob/master/java-checks/src/main/java/org/sonar/java/checks/StringLiteralDuplicatedCheck.java
get method name
public class SomeClass extends IssuableSubscriptionVisitor {
#Override
public List<Tree.Kind> nodesToVisit() {
return ImmutableList.of(Tree.Kind.METHOD);
}
#Override
public void visitNode(Tree tree) {
MethodTree methodTree = (MethodTree) tree;
IdentifierTree methodName = methodTree.simpleName();
// getName from methodName.
}
**get invocation method name**
public class SomeClass extends IssuableSubscriptionVisitor {
public static IdentifierTree methodName(MethodInvocationTree mit) {
IdentifierTree id;
if (mit.methodSelect().is(Tree.Kind.IDENTIFIER)) {
id = (IdentifierTree) mit.methodSelect();
} else {
id = ((MemberSelectExpressionTree) mit.methodSelect()).identifier();
}
return id;
}
#Override
public void visitMethodInvocation(MethodInvocationTree tree) {
IdentifierTree id;
if (tree.methodSelect().is(Tree.Kind.IDENTIFIER)){
id = (IdentifierTree) tree.methodSelect();
} else {
id = ((MemberSelectExpressionTree) tree.methodSelect()).identifier();
}
if(id.name().matches("(.*)[lL]og(.*)")){
//Do nothing -> Ignores method with the "log" in them for scanning
}else {
scan(tree.methodSelect());
scan(tree.typeArguments());
scan(tree.arguments());
}
}
I am new to Spring MVC and Velocity Templates, but I am using them for a project and had some questions. Basically, I'm using some legacy code as my template, but the syntax in the legacy code isn't working for me and I'm not sure why. Our team has a public class called AdminData which looks something like:
public class AdminData {
private long property1;
public void setProperty1 (long property1) {
this.property1 = property1;
}
public long getProperty1() {
return property1;
}
And Java code which looks like this:
ModelAndView model = new ModelAndView("view");
AdminData data = new AdminData();
... // set some properties of data
model.addObject("data", data);
return model;
then in our Velocity Template we reference properties of the data object like so:
${data.property1}
and the value is correctly displayed on the page. Then we have another class called AdminFeatures which looks like:
public class AdminFeatures {
private boolean property2;
public void setProperty2(boolean property2) {
this.property2 = property2;
}
public boolean getProperty2() {
return property2;
}
with essentially the same Java code for setting up the model and view as we used for AdminData. The problem I'm running into is that when I try to reference property2 in AdminFeatures in the same way like:
${data.property2}
I am unable to print out the value of the variable. However if I use the syntax:
$data.getProperty2() // ... or ${data.getProperty2()}
then I am able to print the value of the property. Does this have something to do with difference between boolean vs. Boolean in Java? Or the fact the property1 is a long while property2 is a boolean?
Thank you.
Is because property2 is a boolean. The standard method convention for getter/setter for a boolean type are of the form isProperty and setProperty.
So your AdminFeatures class should be:
public class AdminFeatures {
private boolean property2;
public void setProperty2(boolean property2) {
this.property2 = property2;
}
public boolean isProperty2() {
return property2;
}
I'm just beginning to experiment with Android Development with SimpleXML and thought it was going quite well until I hit a snag. The code below produces an exception of
W/System.err(665): org.simpleframework.xml.core.ConstructorException: Can not construct inner class
I've looked through the questions on inner classes and think I understand why you would use them (not that mine was necessarily intentional) but despite moving my code round to try and avoid usage I'm still a little stuck and would appreciate any help.
Source Code:
public class InCaseOfEmergencyMedAlertAllergiesActivity extends Activity {
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
Serializer serializer = new Persister();
InputStream xmlstream = this.getResources().openRawResource(R.raw.sample_data_allergies);
try {
medalertdata allergyObject = serializer.read(medalertdata.class, xmlstream);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
setContentView(R.layout.allergies);
}
#Root
public class medalertdata {
#ElementList
private List<allergy> allergyList;
public List getAllergies() {
return allergyList;
}
}
#Root
public class allergy{
#Element
private String to;
#Element
private Boolean medical;
#Element
private String notes;
public allergy(String to, Boolean medical, String notes){
this.to = to;
this.medical = medical;
this.notes = notes;
}
public String getTo() {
return to;
}
public Boolean getMedical() {
return medical;
}
public String getNotes() {
return notes;
}
}
}
With the XML file referenced structured as:
<?xml version="1.0" encoding="ISO-8859-1"?>
<medalertdata>
<allergy>
<to>Penicillin</to>
<medical>true</medical>
<notes></notes>
</allergy>
<allergy>
<to>Bee Stings</to>
<medical>false</medical>
<notes>Sample</notes>
</allergy>
</medalertdata>
Is the problem with how I have annotated the SimpleXML classes or where I am trying to read them? Thanks!
I ran into this too while reading some deeply nested XML data into Java objects (and wanting to keep the object structure simple by defining the classes in the same file).
The solution (that doesn't involve splitting into separate files) was to make the nested classes static. (In other words, convert inner classes into static nested classes.) Kinda obvious in retrospective.
Example;
Nested structure:
// ScoreData
// Sport
// Category
// Tournament
Java:
#Root
public class ScoreData {
#ElementList(entry = "Sport", inline = true)
List<Sport> sport;
static class Sport {
#ElementList(entry = "Category", inline = true)
List<Category> category;
}
// ...
}
Disclaimer: I realise OP got the problem solved already, but maybe this helps others who run into
org.simpleframework.xml.core.ConstructorException: Can not construct inner class and don't want to define the classes in separate files as Peter's answer suggests.
Try removing #Root from the allergy class.
Also: do you have this two classes each in it's separate file: allergy.java and medalertdata.java?
I have a question regarding the best way to implement this. I'm going to describe my current implementation and how I seem to have painted myself into a corner:
I have an abstract class called Package:
public abstract class Package {
protected String description;
protected String packagingCode;
protected Dimension dimensions;
protected Weight weight;
protected Package() {
this.description = null;
this.packagingCode = null;
this.dimensions = null;
this.weight = null;
}
protected Package(String description, String packagingCode, Dimension dimensions, Weight weight) throws ShippingException {
this.description = description;
this.packagingCode = packagingCode;
this.dimensions = dimensions;
this.weight = weight;
String exceptionMessage = "";
if(!meetsWeightRequirements()) {
exceptionMessage = "This package's weight exceeds limits. ";
}
if(!meetsDimensionalRequirements()) {
exceptionMessage += "This package's dimensions exceed limits.";
}
if(!StringUtils.isEmpty(exceptionMessage)) {
throw new ShippingException(exceptionMessage);
}
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getPackagingCode() {
return packagingCode;
}
public void setPackagingCode(String packagingCode) {
this.packagingCode = packagingCode;
}
public Dimension getPackageDimensions() {
return dimensions;
}
public void setPackageDimensions(Dimension dimensions) throws ShippingException {
this.dimensions = dimensions;
if(!meetsDimensionalRequirements()) {
this.dimensions = null;
throw new ShippingException("This package's dimensions exceed limits.");
}
}
public Weight getPackageWeight() {
return weight;
}
public void setPackageWeight(Weight weight) throws ShippingException {
this.weight = weight;
if(!meetsWeightRequirements()) {
this.weight = null;
throw new ShippingException("This package's weight exceeds limits.");
}
}
public abstract boolean meetsWeightRequirements();
public abstract boolean meetsDimensionalRequirements();
}
Then I have classes that extend this abstract class like so:
public class WeightBasedPackage extends Package {
public boolean meetsWeightRequirements() {
Weight weight = this.getPackageWeight();
boolean meetsRequirements = false;
if(weight != null) {
meetsRequirements = (weight.getWeight() > 0);
}
return meetsRequirements;
}
public boolean meetsDimensionalRequirements() {
return true;
}
}
I have another object (ShipRequest) that maintains a List of Packages (List<Package>). I also have a services (eg WeightBasedPackageShipService) that uses this object and can access this list of packages. This implementation has worked fine because the services don't really care what type of package it is. The only difference between the packages is the way they implement the abstract methods.
Now here is where the problem comes in. I created a new class:
public class OrderQuantityPackage extends Package {
int quantity;
public OrderQuantityPackage() {
super();
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public int getQuantity() {
return this.quantity;
}
public boolean meetsWeightRequirements() {
return true;
}
public boolean meetsDimensionalRequirements() {
return true;
}
}
Which has a quantity field. I need to access this field in the service (OrderQuantityPackageShipService). However, since it is of type Package I have to cast it (it seems kinda kludgey).
My question is, how do I implement this in a better fashion (so I don't have to cast) and also ensure type-safety (So that if you are using OrderQuantityPackageShipService, the package must be of type OrderQuantityPackage). I thought about using Generics, but it seems a little to kludgey for what I am trying to do (ShipRequest has a bunch of other attributes and it seemed strange to genericize it based on the type of package).
Thanks.
public abstract class Package {
protected String description; // These shouldn't be private fields instead of protected?
protected String packagingCode; // Nah, I don't think so, otherwise how could I store a value into the Quantity field? =P
protected Dimension dimensions;
protected Weight weight;
protected int quantity;
// Constructors, getters and setters...
public virtual int getQuantity {
throw new NotImplementedException();
}
public virtual int setQuantity(int quantity) {
throw new NotImplementedException();
}
}
public final class OrderQuantityPackage extends Package {
public override int getQuantity {
return super.quantity;
}
public override void setQuantity(int quantity) {
super.quantity = quantity;
}
}
I'm not completely sure about the syntax though, and neither about the NotImplementedException, but I hope you get the idea. So, any Package derived class that needs or require a quantity may do so by overriding the getter and setter of the Quantity property.
No exception should be thrown as of where the Quantity won't be required, it shouldn't get called, so no exception shall be thrown. Furthermore, it testifies that your model only does what it is required when times come.
In addition to it, OrderQuantityShipService shouldn't require a Weight property within the OrderQuantityPackage, and as written by Vivin, one could access the weight anyway.
Otherwise, a simple cast within your service should do it. It is no dirty way to go to use casting. For instance, one must cast the sender object within an event handler to the proper control type he wishes to check for name, state or other property values! The most general class is then passed on to the event, and one must cast... And this, that is not me who said to opt this way, these are software engineers!...
EDIT Vivin, how do one cast from a data type to another in JAVA, is it as in C/C++/C# ?
CastedType variable = (CastedType)TypeCast;
Short Answer: Dependency Inversion
You have a OrderQuantityPackageShipService class that requires certain features from the objects that it processes. So OrderQuantityPackageShipService should be the one specifying those requirements. Typically this is done with an interface. If it is very specific to the service, create the interface nested. ie:
class OrderQuantityPackageShipService {
//...
interface QuantityPackage {
int getQuantity();
// ...
}
}
if it can be used in a consistent manner by other services, define it outside of the OrderQuantityPackageShipService class.
Then have certain packages implement that interface...
Maybe you should create an abstract service and extend it for the different kinds of packages to handle. You could have the handling method be abstract and have each kind of service know what to do with the corresponding package. If you're not to mix types of packages then this might work.
One thing I can think of is why would you need to access the quantity attribute in the class OrderQuantityPackageShipService ? As I look at it you have a getter and setter for each attribute of the class Package. Are these getters and setters really needed ? Having getters/setters for all those attributes doesn't go well with encapsulation.
Can you think of providing public methods in Package class that operate at a higher level and don't expose the internal attributes ? Wouldn't that help ?